waf_unit_test

Unit testing system for C/C++/D providing test execution:

  • in parallel, by using waf -j
  • partial (only the tests that have changed) or full (by using waf --alltests)

The tests are declared by adding the test feature to programs:

def options(opt):
        opt.load('compiler_cxx waf_unit_test')
def configure(conf):
        conf.load('compiler_cxx waf_unit_test')
def build(bld):
        bld(features='cxx cxxprogram test', source='main.cpp', target='app')
        # or
        bld.program(features='test', source='main2.cpp', target='app2')

When the build is executed, the program ‘test’ will be built and executed without arguments. The success/failure is detected by looking at the return code. The status and the standard output/error are stored on the build context.

The results can be displayed by registering a callback function. Here is how to call the predefined callback:

def build(bld):
        bld(features='cxx cxxprogram test', source='main.c', target='app')
        from waflib.Tools import waf_unit_test
        bld.add_post_fun(waf_unit_test.summary)
waflib.Tools.waf_unit_test.make_test(self)[source]

Task generator method

Create the unit test task. There can be only one unit test task by task generator.
feature:test
class waflib.Tools.waf_unit_test.utest(*k, **kw)[source]

Bases: waflib.Task.Task

Execute a unit test

color = 'PINK'
after = ['vnum', 'inst']
vars = []
runnable_status()[source]

Always execute the task if waf –alltests was used or no tests if waf --notests was used

__doc__ = '\n\tExecute a unit test\n\t'
__module__ = 'waflib.Tools.waf_unit_test'
hcode = '\tdef run(self):\n\t\t"""\n\t\tExecute the test. The execution is always successful, but the results\n\t\tare stored on ``self.generator.bld.utest_results`` for postprocessing.\n\t\t"""\n\n\t\tfilename = self.inputs[0].abspath()\n\t\tself.ut_exec = getattr(self.generator, \'ut_exec\', [filename])\n\t\tif getattr(self.generator, \'ut_fun\', None):\n\t\t\t# FIXME waf 1.8 - add a return statement here?\n\t\t\tself.generator.ut_fun(self)\n\n\t\ttry:\n\t\t\tfu = getattr(self.generator.bld, \'all_test_paths\')\n\t\texcept AttributeError:\n\t\t\t# this operation may be performed by at most #maxjobs\n\t\t\tfu = os.environ.copy()\n\n\t\t\tlst = []\n\t\t\tfor g in self.generator.bld.groups:\n\t\t\t\tfor tg in g:\n\t\t\t\t\tif getattr(tg, \'link_task\', None):\n\t\t\t\t\t\ts = tg.link_task.outputs[0].parent.abspath()\n\t\t\t\t\t\tif s not in lst:\n\t\t\t\t\t\t\tlst.append(s)\n\n\t\t\tdef add_path(dct, path, var):\n\t\t\t\tdct[var] = os.pathsep.join(Utils.to_list(path) + [os.environ.get(var, \'\')])\n\n\t\t\tif Utils.is_win32:\n\t\t\t\tadd_path(fu, lst, \'PATH\')\n\t\t\telif Utils.unversioned_sys_platform() == \'darwin\':\n\t\t\t\tadd_path(fu, lst, \'DYLD_LIBRARY_PATH\')\n\t\t\t\tadd_path(fu, lst, \'LD_LIBRARY_PATH\')\n\t\t\telse:\n\t\t\t\tadd_path(fu, lst, \'LD_LIBRARY_PATH\')\n\t\t\tself.generator.bld.all_test_paths = fu\n\n\n\t\tcwd = getattr(self.generator, \'ut_cwd\', \'\') or self.inputs[0].parent.abspath()\n\n\t\ttestcmd = getattr(Options.options, \'testcmd\', False)\n\t\tif testcmd:\n\t\t\tself.ut_exec = (testcmd % self.ut_exec[0]).split(\' \')\n\n\t\tproc = Utils.subprocess.Popen(self.ut_exec, cwd=cwd, env=fu, stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE)\n\t\t(stdout, stderr) = proc.communicate()\n\n\t\ttup = (filename, proc.returncode, stdout, stderr)\n\t\tself.generator.utest_result = tup\n\n\t\ttestlock.acquire()\n\t\ttry:\n\t\t\tbld = self.generator.bld\n\t\t\tLogs.debug("ut: %r", tup)\n\t\t\ttry:\n\t\t\t\tbld.utest_results.append(tup)\n\t\t\texcept AttributeError:\n\t\t\t\tbld.utest_results = [tup]\n\t\tfinally:\n\t\t\ttestlock.release()\n'
waflib.Tools.waf_unit_test.summary(bld)[source]

Display an execution summary:

def build(bld):
bld(features=’cxx cxxprogram test’, source=’main.c’, target=’app’) from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.summary)
waflib.Tools.waf_unit_test.set_exit_code(bld)[source]

If any of the tests fail waf will exit with that exit code. This is useful if you have an automated build system which need to report on errors from the tests. You may use it like this:

def build(bld):
bld(features=’cxx cxxprogram test’, source=’main.c’, target=’app’) from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.set_exit_code)
waflib.Tools.waf_unit_test.options(opt)[source]

Provide the --alltests, --notests and --testcmd command-line options.

waflib.Tools.waf_unit_test.feature(*k)

Decorator: register a task generator method that will be executed when the object attribute ‘feature’ contains the corresponding key(s):

from waflib.Task import feature
@feature('myfeature')
def myfunction(self):
        print('that is my feature!')
def build(bld):
        bld(features='myfeature')
Parameters:k (list of string) – feature names
waflib.Tools.waf_unit_test.after_method(*k)

Decorator: register a task generator method which will be executed after the functions of given name(s):

from waflib.TaskGen import feature, after
@feature('myfeature')
@after_method('fun2')
def fun1(self):
        print('feature 1!')
@feature('myfeature')
def fun2(self):
        print('feature 2!')
def build(bld):
        bld(features='myfeature')
Parameters:k (list of string) – method names

Features defined in this module:

Previous topic

ruby

Next topic

tex

This Page