Commit 394951ad by Patrick Steinhardt

tests: allow for simple data-driven tests

Right now, we're not able to use data-driven tests at all. E.g.
given a set of tests which we'd like to repeat with different
test data, one has to hand-write any outer loop that iterates
over the test data and then call each of the test functions. Next
to being bothersome, this also has the downside that error
reporting is quite lacking, as one never knows which test data
actually produced failures.

So let's implement the ability to re-run complete test modules
with changing test data. To retain backwards compatibility and
enable trivial addition of new runs with changed test data, we
simply extend clar's generate.py. Instead of scanning for a
single `_initialize` function, each test module may now implement
multiple `_initialize_foo` functions. The generated test harness
will then run all test functions for each of the provided
initializer functions, making it possible to provide different
test data inside of each of the initializer functions. Example:

```
void test_git_example__initialize_with_nonbare_repo(void)
{
	g_repo = cl_git_sandbox_init("testrepo");
}

void test_git_example__initialize_with_bare_repo(void)
{
	g_repo = cl_git_sandbox_init("testrepo.git");
}

void test_git_example__cleanup(void)
{
	cl_git_sandbox_cleanup();
}

void test_git_example__test1(void)
{
	test1();
}

void test_git_example__test2(void)
{
	test2();
}
```

Executing this test module will cause the following output:

```
$ ./libgit2_clar -sgit::example
git::example (with nonbare repo)..
git::example (with bare repo)..
```
parent e50d138e
...@@ -24,8 +24,8 @@ class Module(object): ...@@ -24,8 +24,8 @@ class Module(object):
def render(self): def render(self):
out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n" out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n"
if self.module.initialize: for initializer in self.module.initializers:
out += "extern %s;\n" % self.module.initialize['declaration'] out += "extern %s;\n" % initializer['declaration']
if self.module.cleanup: if self.module.cleanup:
out += "extern %s;\n" % self.module.cleanup['declaration'] out += "extern %s;\n" % self.module.cleanup['declaration']
...@@ -41,7 +41,19 @@ class Module(object): ...@@ -41,7 +41,19 @@ class Module(object):
class InfoTemplate(Template): class InfoTemplate(Template):
def render(self): def render(self):
return Template( templates = []
initializers = self.module.initializers
if len(initializers) == 0:
initializers = [ None ]
for initializer in initializers:
name = self.module.clean_name()
if initializer and initializer['short_name'].startswith('initialize_'):
variant = initializer['short_name'][len('initialize_'):]
name += " (%s)" % variant.replace('_', ' ')
template = Template(
r""" r"""
{ {
"${clean_name}", "${clean_name}",
...@@ -49,14 +61,17 @@ class Module(object): ...@@ -49,14 +61,17 @@ class Module(object):
${cleanup}, ${cleanup},
${cb_ptr}, ${cb_count}, ${enabled} ${cb_ptr}, ${cb_count}, ${enabled}
}""" }"""
).substitute( ).substitute(
clean_name = self.module.clean_name(), clean_name = name,
initialize = self._render_callback(self.module.initialize), initialize = self._render_callback(initializer),
cleanup = self._render_callback(self.module.cleanup), cleanup = self._render_callback(self.module.cleanup),
cb_ptr = "_clar_cb_%s" % self.module.name, cb_ptr = "_clar_cb_%s" % self.module.name,
cb_count = len(self.module.callbacks), cb_count = len(self.module.callbacks),
enabled = int(self.module.enabled) enabled = int(self.module.enabled)
) )
templates.append(template)
return ','.join(templates)
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
...@@ -86,7 +101,7 @@ class Module(object): ...@@ -86,7 +101,7 @@ class Module(object):
regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE) regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE)
self.callbacks = [] self.callbacks = []
self.initialize = None self.initializers = []
self.cleanup = None self.cleanup = None
for (declaration, symbol, short_name) in regex.findall(contents): for (declaration, symbol, short_name) in regex.findall(contents):
...@@ -96,8 +111,8 @@ class Module(object): ...@@ -96,8 +111,8 @@ class Module(object):
"symbol" : symbol "symbol" : symbol
} }
if short_name == 'initialize': if short_name.startswith('initialize'):
self.initialize = data self.initializers.append(data)
elif short_name == 'cleanup': elif short_name == 'cleanup':
self.cleanup = data self.cleanup = data
else: else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment