summaryrefslogtreecommitdiff
path: root/tests-clar/clar
diff options
context:
space:
mode:
authorVicent Martí <tanoku@gmail.com>2012-01-24 20:35:15 -0800
committerVicent Martí <tanoku@gmail.com>2012-01-24 20:35:15 -0800
commit3fd1520cd4d8b4d6b6493a7d3dc393ffd9abf1db (patch)
tree51b29f5d8ffeb31ba751ab2a099e4f2a32d4be07 /tests-clar/clar
parenta9fe8ae0ee1ddcc289fad53f1a671f02a3e9a88f (diff)
downloadlibgit2-3fd1520cd4d8b4d6b6493a7d3dc393ffd9abf1db.tar.gz
Rename the Clay test suite to Clar
Clay is the name of a programming language on the makings, and we want to avoid confusions. Sorry for the huge diff!
Diffstat (limited to 'tests-clar/clar')
-rwxr-xr-xtests-clar/clar309
1 files changed, 309 insertions, 0 deletions
diff --git a/tests-clar/clar b/tests-clar/clar
new file mode 100755
index 000000000..a718a00ec
--- /dev/null
+++ b/tests-clar/clar
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+
+from __future__ import with_statement
+from string import Template
+import re, fnmatch, os
+
+VERSION = "0.10.0"
+
+TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*void\s*\))\s*\{"
+
+EVENT_CB_REGEX = re.compile(
+ r"^(void\s+clar_on_(\w+)\(\s*void\s*\))\s*\{",
+ re.MULTILINE)
+
+SKIP_COMMENTS_REGEX = re.compile(
+ r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+ re.DOTALL | re.MULTILINE)
+
+CLAR_HEADER = """
+/*
+ * Clar v%s
+ *
+ * This is an autogenerated file. Do not modify.
+ * To add new unit tests or suites, regenerate the whole
+ * file with `./clar`
+ */
+""" % VERSION
+
+CLAR_EVENTS = [
+ 'init',
+ 'shutdown',
+ 'test',
+ 'suite'
+]
+
+def main():
+ from optparse import OptionParser
+
+ parser = OptionParser()
+
+ parser.add_option('-c', '--clar-path', dest='clar_path')
+ parser.add_option('-v', '--report-to', dest='print_mode', default='default')
+
+ options, args = parser.parse_args()
+
+ for folder in args or ['.']:
+ builder = ClarTestBuilder(folder,
+ clar_path = options.clar_path,
+ print_mode = options.print_mode)
+
+ builder.render()
+
+
+class ClarTestBuilder:
+ def __init__(self, path, clar_path = None, print_mode = 'default'):
+ self.declarations = []
+ self.suite_names = []
+ self.callback_data = {}
+ self.suite_data = {}
+ self.event_callbacks = []
+
+ self.clar_path = os.path.abspath(clar_path) if clar_path else None
+
+ self.path = os.path.abspath(path)
+ self.modules = [
+ "clar_sandbox.c",
+ "clar_fixtures.c",
+ "clar_fs.c"
+ ]
+
+ self.modules.append("clar_print_%s.c" % print_mode)
+
+ print("Loading test suites...")
+
+ for root, dirs, files in os.walk(self.path):
+ module_root = root[len(self.path):]
+ module_root = [c for c in module_root.split(os.sep) if c]
+
+ tests_in_module = fnmatch.filter(files, "*.c")
+
+ for test_file in tests_in_module:
+ full_path = os.path.join(root, test_file)
+ test_name = "_".join(module_root + [test_file[:-2]])
+
+ with open(full_path) as f:
+ self._process_test_file(test_name, f.read())
+
+ if not self.suite_data:
+ raise RuntimeError(
+ 'No tests found under "%s"' % folder_name)
+
+ def render(self):
+ main_file = os.path.join(self.path, 'clar_main.c')
+ with open(main_file, "w") as out:
+ out.write(self._render_main())
+
+ header_file = os.path.join(self.path, 'clar.h')
+ with open(header_file, "w") as out:
+ out.write(self._render_header())
+
+ print ('Written Clar suite to "%s"' % self.path)
+
+ #####################################################
+ # Internal methods
+ #####################################################
+
+ def _render_cb(self, cb):
+ return '{"%s", &%s}' % (cb['short_name'], cb['symbol'])
+
+ def _render_suite(self, suite):
+ template = Template(
+r"""
+ {
+ "${clean_name}",
+ ${initialize},
+ ${cleanup},
+ ${cb_ptr}, ${cb_count}
+ }
+""")
+
+ callbacks = {}
+ for cb in ['initialize', 'cleanup']:
+ callbacks[cb] = (self._render_cb(suite[cb])
+ if suite[cb] else "{NULL, NULL}")
+
+ return template.substitute(
+ clean_name = suite['name'].replace("_", "::"),
+ initialize = callbacks['initialize'],
+ cleanup = callbacks['cleanup'],
+ cb_ptr = "_clar_cb_%s" % suite['name'],
+ cb_count = suite['cb_count']
+ ).strip()
+
+ def _render_callbacks(self, suite_name, callbacks):
+ template = Template(
+r"""
+static const struct clar_func _clar_cb_${suite_name}[] = {
+ ${callbacks}
+};
+""")
+ callbacks = [
+ self._render_cb(cb)
+ for cb in callbacks
+ if cb['short_name'] not in ('initialize', 'cleanup')
+ ]
+
+ return template.substitute(
+ suite_name = suite_name,
+ callbacks = ",\n\t".join(callbacks)
+ ).strip()
+
+ def _render_event_overrides(self):
+ overrides = []
+ for event in CLAR_EVENTS:
+ if event in self.event_callbacks:
+ continue
+
+ overrides.append(
+ "#define clar_on_%s() /* nop */" % event
+ )
+
+ return '\n'.join(overrides)
+
+ def _render_header(self):
+ template = Template(self._load_file('clar.h'))
+
+ declarations = "\n".join(
+ "extern %s;" % decl
+ for decl in sorted(self.declarations)
+ )
+
+ return template.substitute(
+ extern_declarations = declarations,
+ )
+
+ def _render_main(self):
+ template = Template(self._load_file('clar.c'))
+ suite_names = sorted(self.suite_names)
+
+ suite_data = [
+ self._render_suite(self.suite_data[s])
+ for s in suite_names
+ ]
+
+ callbacks = [
+ self._render_callbacks(s, self.callback_data[s])
+ for s in suite_names
+ ]
+
+ callback_count = sum(
+ len(cbs) for cbs in self.callback_data.values()
+ )
+
+ return template.substitute(
+ clar_modules = self._get_modules(),
+ clar_callbacks = "\n".join(callbacks),
+ clar_suites = ",\n\t".join(suite_data),
+ clar_suite_count = len(suite_data),
+ clar_callback_count = callback_count,
+ clar_event_overrides = self._render_event_overrides(),
+ )
+
+ def _load_file(self, filename):
+ if self.clar_path:
+ filename = os.path.join(self.clar_path, filename)
+ with open(filename) as cfile:
+ return cfile.read()
+
+ else:
+ import zlib, base64, sys
+ content = CLAR_FILES[filename]
+
+ if sys.version_info >= (3, 0):
+ content = bytearray(content, 'utf_8')
+ content = base64.b64decode(content)
+ content = zlib.decompress(content)
+ return str(content)
+ else:
+ content = base64.b64decode(content)
+ return zlib.decompress(content)
+
+ def _get_modules(self):
+ return "\n".join(self._load_file(f) for f in self.modules)
+
+ def _skip_comments(self, text):
+ def _replacer(match):
+ s = match.group(0)
+ return "" if s.startswith('/') else s
+
+ return re.sub(SKIP_COMMENTS_REGEX, _replacer, text)
+
+ def _process_test_file(self, suite_name, contents):
+ contents = self._skip_comments(contents)
+
+ self._process_events(contents)
+ self._process_declarations(suite_name, contents)
+
+ def _process_events(self, contents):
+ for (decl, event) in EVENT_CB_REGEX.findall(contents):
+ if event not in CLAR_EVENTS:
+ continue
+
+ self.declarations.append(decl)
+ self.event_callbacks.append(event)
+
+ def _process_declarations(self, suite_name, contents):
+ callbacks = []
+ initialize = cleanup = None
+
+ regex_string = TEST_FUNC_REGEX % suite_name
+ regex = re.compile(regex_string, re.MULTILINE)
+
+ for (declaration, symbol, short_name) in regex.findall(contents):
+ data = {
+ "short_name" : short_name,
+ "declaration" : declaration,
+ "symbol" : symbol
+ }
+
+ if short_name == 'initialize':
+ initialize = data
+ elif short_name == 'cleanup':
+ cleanup = data
+ else:
+ callbacks.append(data)
+
+ if not callbacks:
+ return
+
+ tests_in_suite = len(callbacks)
+
+ suite = {
+ "name" : suite_name,
+ "initialize" : initialize,
+ "cleanup" : cleanup,
+ "cb_count" : tests_in_suite
+ }
+
+ if initialize:
+ self.declarations.append(initialize['declaration'])
+
+ if cleanup:
+ self.declarations.append(cleanup['declaration'])
+
+ self.declarations += [
+ callback['declaration']
+ for callback in callbacks
+ ]
+
+ callbacks.sort(key=lambda x: x['short_name'])
+ self.callback_data[suite_name] = callbacks
+ self.suite_data[suite_name] = suite
+ self.suite_names.append(suite_name)
+
+ print(" %s (%d tests)" % (suite_name, tests_in_suite))
+
+
+
+CLAR_FILES = {
+"clar.c" : r"""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""",
+"clar_print_default.c" : r"""eJyFU01P4zAQPSe/YqgU1a5Cuadi98ap4rLaE6DIxA5YSu3InnQPK/479jgFB9FycuZ53vObj5QeBeoOjlZL6Abh2tFpg602Gln4AFQe285OBmuIsZ80qhPQWeMRulfhYJMujDgoz8v/ZcGiJP+k78qCpHu22lshlYRKJjXfQOUfzaqG+CJfvJCrZgp/UDhUMpAC+laWZ6rwrxNK+8/8XEkElHPWJeBcBQnKmB9YRt6Vn0YfTfJYkCunRuuwpVzPLlqnHPJtpsOp0x7d1GFKowTY0EF2T09CaCyHO6GHyamG+hokeO6q8k1TeWCV5/AQgko+wcM1hiOml0VBqte/qNAsjr2I4cpYkMp3To+o7YLS6yFnDNqE8U2HZ+W+6MzowhecFmHOS009+BfK0j2w+SJ7HK5u4f7vfs+D/DmdLJ0vp3N5f6yJTlm+5sl62Me0M1klCehD35X8uj+RsFsixMlWuuqC38SG37C+W0MD6+36B380Ifb9f0gmbjZgrB1hc7Pc3uTokrR4Dru6kA6DqGG73ZLwUbSDDlfCvYw7Cn38KVmMa0gzK479XJ5HGWZBeE0UnjjKSDaHb+U7mrWGAw==""",
+"clar_print_tap.c" : r"""eJyNVMFu2zAMPVtfwbgIYBu2gWK3BmuxnYthh+02wFBtORXmSIYkZxiG/vso2m6lJF12skk9ko+PlJh13MkWjlp20A7cNKORyjVSSZfhDzhhXdPqSbkSvG0n6cTqaLWyDtpnbqCYDxQ/CJuzPyzJfMr8LXy3ugLgiW/FEYU+S799+gpHYazUCm4//FBpvmMvjL1D2T5PrtO/1HXa3iGM0WZ2/A/d2BcE7xhLZA/ZJkqYvPZwAyO3VnTAhwG2HRHLbI7NlAFJbCwRgxVRYM/lgIEYxA9a7U+jg4IlxiVxtjXNbV1vu/Nq78tIaUlDNR3WEVtnptbNMAJAQZ9AOkR7Lda6AFVVzSMLfDhzy/cC7mBr35qo7udeDnYfw63A8Uv3+460OMtGowE4y0b+GOqbhwtQ74+RPYp+Cen9MXKQakV2IdL7G5TjSZh8XY/lqBO2NXJ0fqM3H+HL98fHcFkAAsApgeAoj5Wu6/ra5dCKVie8sLQP/hrOF2I2ifXsmNePJryW2lq/hNVCDIkvK/oAqdIO9M8UxUjx48/ChK8mlmMJ0SdyRozaLDtnsysd0Fizy29ORPMGiqJAkv5DCga4f5fgT0gnKoE7WXqBqcCRN4PEI272445MzIQB3i5hWd9+oWHxNZrwtUk/o0iAvxug/T2eAqiET5HPOYXqssV8YX8BFTvXlQ==""",
+"clar_sandbox.c" : r"""eJyNVV1P20AQfLZ/xRIkYpNATItaVSkPlaBVVEoiEgQSRJaxz+SEfY7uLmkD4r931+fEHwRahBST3Zudmb0xSgeahxDOAgl+mATSnwd6dnvsffk07du2MmUutM2VvwwSHvk6nedNTpgJpc3RffrCtZ9tazz5NvEnoDSetngMDkE4VO7CntIu7JyA59qWJZleSAHeum9n7A/Gp4NLPHCotJ9mEXObfcWzE4QhU6pAvfaHP104Idi+/VLjHHNR5ZszvV/EMZNdUPyJ+RoSJh4M9V0ei4jF4F8PLj5+sK0Cx6gsupdoUJgthIYTOO43egw+E0s0SqrbKfagIVZr8muEulpdoKf848x8Xo3PLkeXw++D87OWDdYLSgSrmMRJb5xJcDjieH3g8LUc34dOh7s5fGM2Nj8wjQ/OhgifojGWMRm/JFPplOZiwWhKXnm9Xmo1I1CmFOF85ay9w1J37RxBV5ZkWS82/tpWbx8GMegZo24uM5EytC3KmBJt9DNYQSBWesbFQxe0XIHOYKEY9HA+7PfsN0i1qN4qeDVpmWKNWYUYktpliWIG+gfTE5bORwTqnF4PL09dc6wLBq5x+XaZiHhsdE1mXIFaKc3SjaCEPzIUUNNC4sOFlLlwLlmoMyy+I+7wTWWH78la/3lwVA3AMuMR5JFeCBWI6D7749B3eUyJQCXv3pQC1L7z2qVqvBoYiWoiwhmqQJZIs2JIrHyZVsCaKUQ/eRL5BQWjdMOjcnup4OuAJ3lyWjkeWXOT/7QobZvIrl8a9YCXHEy8s7hKy8UAVd885JZtIRhOQ7/xoS6iqf4ZcPUikyku7YnldGnRo+F4cAOY1N+BjEAlgZoxlS+5EmXrVZRJRBni5j54sY+7fB+W1ShBu9feRG2ziAYGKTuAoym9cbHfDKrXO50SjO7R+tqVXdAhpt1yOducxTHYtMUyYpQ+Ykzmvvrndhr/GMx6DAJdu+px77PnbT1QCTieosE1nujpxdX5+atDhYFlquoXOEf4/wjB3t62O7/9/hGKyVWV6FYvavT+AhbcW38=""",
+"clar_fixtures.c" : r"""eJyFUV1LwzAUfW5+xZU9rLUVJ4ggZQ9DFAUfZEwQSglZmrBAl5Qkk6n43236tWbKfMvNOfecc+81llhBgSppLNAN0XCOuNjbnWa4InYTjpE1MSzxuD1Vki2L0BcKTKfn0EYgu57d3uRpjYhPhi1opSwumUwRCvo3zMFYXT9C5xA5stWSVh9hI5FAa+wUFG//osgJCA5tmQ1SF3CVw9kcppfTCAWBj8ZxDg3UN4/zZ7MaHBrHSBw7vpcJ4mGS5Ijtai9qnannNqk1q7myXU+KvhGaCF4wDnfPiyV+eHpbvS7v8cti9YjGq6Yl7lzCkxfo1L0j/lJOwOtrUrwrUcDBBRsii7Xan3bjBlNVL2WUzuMkgGlJdLuIP21oyYjcVf/a6G3ozXTQPRqmsZkwWQiOfgAVGffP""",
+"clar_fs.c" : r"""eJylVdtu20YQfSa/YkAD8TKWY8dJX6L0wXDEVqgsBhINN7UFhiGX1qIkl9hd+dLG/57ZCynJUWEkfZE0s7NnZufMGe2xsqAlpJfj6ZsT399DgzUUojhKo8npb3Mg+ud8PBlNE/hq/NP4LJ5G49n5aTKOp71zNJvFs4vx06DzPz6MZ6HvS5UplkO+zAS89EtWUd7KtM3UkuS8kcqdGE/o/+t71tYm/ArTi8lk6HuS/UNTBRVtbtRyAGzo+x4rgaQ2zMaFvucJqlaicdd8z15AHKkE/rbxIQI6+DqrKp4TF3YAJ2GH/AxwTeu8fTBRA0jtl0Xp0K+sucAsx9suzPPauX2v5AIIMxYweO9AhnBwwELAbvTFXLGFrmf/aF+X4/Uu2L++3scEjwjmitRnQ/+x7/0tZ0XXecIaBTUv6AC22i/5SuRPnQWVynAy/z3CSYg/zpPZxVkCJQLp4m2YvYqVbJHrEHU7bJgG+y7IZNBQf1HBz2nNxQN5oeEHoDnnJdlOHYa2aa18dRetmlxziI8ZOl8bCV5ruk3u3ptw9OlUnaeMquxGorOfd/OcKs2kpEKlBFuMibHUuKUCm8gbW1aoOTge4HFwyZqC30l4EgdlhmYR+J4tVVBK1q0wpnv0U4JkKmqygxTDQEdfFKcfRpNRMsKx6zgzM7oLL+c4oz9A80aSs/jjp40U6bpmA46t0vgVzZpVS7TLApg3lOwe55A6ivMqE04hwcsgtCB7tJK0KxdH0pdLWlUpXylii3IVZuLm9mphsPXg6gsrqeXECtwH+Kl7jF96sLj4m6z1i773cGw1VLYCb5dEqoIKodnzgvmDVLQGtLl4B5/t7c+Q40ZwFL66bgLNmUfvmSKHr0Onsg5eT4LFp/c0vyWm1uPFwBTdBd9lTGGwvjCAF7b+Ad4b9mq9HP05TubJaXIxJ/b8f3DZU2lNU9Ivi+G2VNcL1dopLh3dt17IuC0LpHVDwuvA9TLtT21LrHm1EXlo9ly/s/4rwC5C1z00g6MvrDnK22DovCYoOJz1jpPFpsaN6412udkJndTNwdtF/zdiFF6vpMJxlNKIfD12hjQj7MiwD4qD7jkovbfcSEvtlVlTfOH3uxX+rKg3NL3B0dvFrh6I+rselNtN6F68oxk/+2araVBLuv3SZ6RvZL5q3BVi9r52bTgeUfZNwUr/G9kaoSs=""",
+"clar.h" : r"""eJy9Vctu2zAQPEdfwVo9WIIQp9c0DWAENmLACIrUQXojaHIVEZVJlaQaAUX/vSQlP/Rw3PTgk6nlDmd2d0iHPBUMUoTx3XL6iFezbyt8j3EQ2iAX0IsHIRc0LxmgG21YzteX2W0Q/JKcIZoThTHRGpQZBxdcGESlYNxwKZLgwq61jWREoTjlOSR1Sm5ZOruglFSdGANNFS+asxxQZ7LMGSZrqUz0eacBazCY5kBEWYx9bBw3n1H9HUcJqheyID9LsOAtNtUtqDs25Knrj+/CfPF99fQ4w1+nq/vgUJ2D8sqUCsbtMn0MC7JpsTRhTQRby+o9kK26NyAh2J6nQTCJ4wDFaOrnYduGNoQqqdErNxmCqsg55Qb5XqMNaE1ewOZPdpO3rJtSG1zYieKxBagEuSlE7UH7nQjdfkFXiXXLfLGcYexWy8WDX43mpaBeACV5jlJiZ8+u0QiF+zMT9CnqEbvM08Q3R3lnVQHUAENpS4CRXsMJBTXJafoPx+u2/Mr21RFzjYQ0yKgShni3s7rLgP74jzlRhzvToK6iPvOZJzUk4QyDuopOXCoh//E6NZKGbtjD03I5fBU6oMOe90BN6TtE2811+nHTnapjb7c9Q9+CPVF7r3Rhb9biU7qIwUrmUlFnInuafQ8nr0QJLl666r2AAZ8cc8cK7EtbX4bL0fBj0TC959TnGoJYqdyPcSRQAS2dq65HA57zOjZgMsnspiMhLlf7+j7+hsqAEvhw50+w/TP4C4S1nfY="""
+}
+if __name__ == '__main__':
+ main()