def add_test(self, node, args, kwargs, is_base_test):
    if (len(args) != 2):
        raise InterpreterException('test expects 2 arguments, {} given'.format(len(args)))
    if (not isinstance(args[0], str)):
        raise InterpreterException('First argument of test must be a string.')
    exe = args[1]
    if (not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder))):
        if isinstance(exe, mesonlib.File):
            exe = self.func_find_program(node, args[1], {})
        else:
            raise InterpreterException('Second argument must be executable.')
    par = kwargs.get('is_parallel', True)
    if (not isinstance(par, bool)):
        raise InterpreterException('Keyword argument is_parallel must be a boolean.')
    cmd_args = unholder(extract_as_list(kwargs, 'args'))
    for i in cmd_args:
        if (not isinstance(i, (str, mesonlib.File, build.Target))):
            raise InterpreterException('Command line arguments must be strings, files or targets.')
    env = self.unpack_env_kwarg(kwargs)
    should_fail = kwargs.get('should_fail', False)
    if (not isinstance(should_fail, bool)):
        raise InterpreterException('Keyword argument should_fail must be a boolean.')
    timeout = kwargs.get('timeout', 30)
    if ('workdir' in kwargs):
        workdir = kwargs['workdir']
        if (not isinstance(workdir, str)):
            raise InterpreterException('Workdir keyword argument must be a string.')
        if (not os.path.isabs(workdir)):
            raise InterpreterException('Workdir keyword argument must be an absolute path.')
    else:
        workdir = None
    if (not isinstance(timeout, int)):
        raise InterpreterException('Timeout must be an integer.')
    protocol = kwargs.get('protocol', 'exitcode')
    if (protocol not in {'exitcode', 'tap', 'gtest'}):
        raise InterpreterException('Protocol must be "exitcode", "tap", or "gtest".')
    suite = []
    prj = (self.subproject if self.is_subproject() else self.build.project_name)
    for s in mesonlib.stringlistify(kwargs.get('suite', '')):
        if (len(s) > 0):
            s = (':' + s)
        suite.append((prj.replace(' ', '_').replace(':', '_') + s))
    depends = unholder(extract_as_list(kwargs, 'depends'))
    for dep in depends:
        if (not isinstance(dep, (build.CustomTarget, build.BuildTarget))):
            raise InterpreterException('Depends items must be build targets.')
    priority = kwargs.get('priority', 0)
    if (not isinstance(priority, int)):
        raise InterpreterException('Keyword argument priority must be an integer.')
    t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args, env, should_fail, timeout, workdir, protocol, priority)
    if is_base_test:
        self.build.tests.append(t)
        mlog.debug('Adding test', mlog.bold(args[0], True))
    else:
        self.build.benchmarks.append(t)
        mlog.debug('Adding benchmark', mlog.bold(args[0], True))
def add_test(self, node, args, kwargs, is_base_test):
    if (len(args) != 2):
        raise InterpreterException('test expects 2 arguments, {} given'.format(len(args)))
    if (not isinstance(args[0], str)):
        raise InterpreterException('First argument of test must be a string.')
    exe = args[1]
    if (not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder))):
        if isinstance(exe, mesonlib.File):
            exe = self.func_find_program(node, args[1], {})
        else:
            raise InterpreterException('Second argument must be executable.')
    par = kwargs.get('is_parallel', True)
    if (not isinstance(par, bool)):
        raise InterpreterException('Keyword argument is_parallel must be a boolean.')
    cmd_args = unholder(extract_as_list(kwargs, 'args'))
    for i in cmd_args:
        if (not isinstance(i, (str, mesonlib.File, build.Target))):
            raise InterpreterException('Command line arguments must be strings, files or targets.')
    env = self.unpack_env_kwarg(kwargs)
    should_fail = kwargs.get('should_fail', False)
    if (not isinstance(should_fail, bool)):
        raise InterpreterException('Keyword argument should_fail must be a boolean.')
    timeout = kwargs.get('timeout', 30)
    if ('workdir' in kwargs):
        workdir = kwargs['workdir']
        if (not isinstance(workdir, str)):
            raise InterpreterException('Workdir keyword argument must be a string.')
        if (not os.path.isabs(workdir)):
            raise InterpreterException('Workdir keyword argument must be an absolute path.')
    else:
        workdir = None
    if (not isinstance(timeout, int)):
        raise InterpreterException('Timeout must be an integer.')
    protocol = kwargs.get('protocol', 'exitcode')
    if (protocol not in {'exitcode', 'tap', 'gtest'}):
        raise InterpreterException('Protocol must be "exitcode", "tap", or "gtest".')
    suite = []
    prj = (self.subproject if self.is_subproject() else self.build.project_name)
    for s in mesonlib.stringlistify(kwargs.get('suite', )):
        if (len(s) > 0):
            s = (':' + s)
        suite.append((prj.replace(' ', '_').replace(':', '_') + s))
    depends = unholder(extract_as_list(kwargs, 'depends'))
    for dep in depends:
        if (not isinstance(dep, (build.CustomTarget, build.BuildTarget))):
            raise InterpreterException('Depends items must be build targets.')
    priority = kwargs.get('priority', 0)
    if (not isinstance(priority, int)):
        raise InterpreterException('Keyword argument priority must be an integer.')
    t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args, env, should_fail, timeout, workdir, protocol, priority)
    if is_base_test:
        self.build.tests.append(t)
        mlog.debug('Adding test', mlog.bold(args[0], True))
    else:
        self.build.benchmarks.append(t)
        mlog.debug('Adding benchmark', mlog.bold(args[0], True))