Commit 7202ec29e9643b7262d827483d96b9e8708af543

Russell Belfer 2013-03-20T11:47:34

Update to latest Clar

diff --git a/tests-clar/clar.c b/tests-clar/clar.c
index 10bea87..fed87c3 100644
--- a/tests-clar/clar.c
+++ b/tests-clar/clar.c
@@ -331,21 +331,14 @@ clar_test(int argc, char **argv)
 	return _clar.total_errors;
 }
 
-void
-clar__assert(
-	int condition,
+void clar__fail(
 	const char *file,
 	int line,
 	const char *error_msg,
 	const char *description,
 	int should_abort)
 {
-	struct clar_error *error;
-
-	if (condition)
-		return;
-
-	error = calloc(1, sizeof(struct clar_error));
+	struct clar_error *error = calloc(1, sizeof(struct clar_error));
 
 	if (_clar.errors == NULL)
 		_clar.errors = error;
@@ -380,6 +373,20 @@ clar__assert(
 	}
 }
 
+void clar__assert(
+	int condition,
+	const char *file,
+	int line,
+	const char *error_msg,
+	const char *description,
+	int should_abort)
+{
+	if (condition)
+		return;
+
+	clar__fail(file, line, error_msg, description, should_abort);
+}
+
 void clar__assert_equal_s(
 	const char *s1,
 	const char *s2,
@@ -392,8 +399,8 @@ void clar__assert_equal_s(
 
 	if (!match) {
 		char buf[4096];
-		snprint_eq(buf, 4096, "'%s' != '%s'", s1, s2);
-		clar__assert(0, file, line, err, buf, should_abort);
+		snprint_eq(buf, sizeof(buf), "'%s' != '%s'", s1, s2);
+		clar__fail(file, line, err, buf, should_abort);
 	}
 }
 
@@ -407,8 +414,8 @@ void clar__assert_equal_i(
 {
 	if (i1 != i2) {
 		char buf[128];
-		snprint_eq(buf, 128, "%d != %d", i1, i2);
-		clar__assert(0, file, line, err, buf, should_abort);
+		snprint_eq(buf, sizeof(buf), "%d != %d", i1, i2);
+		clar__fail(file, line, err, buf, should_abort);
 	}
 }
 
diff --git a/tests-clar/clar.h b/tests-clar/clar.h
index 2ba6416..d92318b 100644
--- a/tests-clar/clar.h
+++ b/tests-clar/clar.h
@@ -51,17 +51,29 @@ void cl_fixture_cleanup(const char *fixture_name);
 /**
  * Forced failure/warning
  */
-#define cl_fail(desc) clar__assert(0, __FILE__, __LINE__, "Test failed.", desc, 1)
-#define cl_warning(desc) clar__assert(0, __FILE__, __LINE__, "Warning during test execution:", desc, 0)
+#define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1)
+#define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0)
 
 /**
  * Typed assertion macros
  */
 #define cl_assert_equal_s(s1,s2) clar__assert_equal_s((s1),(s2),__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1)
+#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal_s((s1),(s2),__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1)
+
 #define cl_assert_equal_i(i1,i2) clar__assert_equal_i((i1),(i2),__FILE__,__LINE__,#i1 " != " #i2, 1)
+#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal_i((i1),(i2),__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1)
+
 #define cl_assert_equal_b(b1,b2) clar__assert_equal_i(!!(b1),!!(b2),__FILE__,__LINE__,#b1 " != " #b2, 1)
+
 #define cl_assert_equal_p(p1,p2) cl_assert((p1) == (p2))
 
+void clar__fail(
+	const char *file,
+	int line,
+	const char *error,
+	const char *description,
+	int should_abort);
+
 void clar__assert(
 	int condition,
 	const char *file,
diff --git a/tests-clar/generate.py b/tests-clar/generate.py
index c273922..d4fe8f2 100644
--- a/tests-clar/generate.py
+++ b/tests-clar/generate.py
@@ -60,7 +60,10 @@ class Module(object):
 
     def __init__(self, name):
         self.name = name
+
+        self.mtime = 0
         self.enabled = True
+        self.modified = False
 
     def clean_name(self):
         return self.name.replace("_", "::")
@@ -102,17 +105,41 @@ class Module(object):
 
         return self.callbacks != []
 
-    def load(self, path):
+    def refresh(self, path):
+        self.modified = False
+
         try:
+            st = os.stat(path)
+
+            # Not modified
+            if st.st_mtime == self.mtime:
+                return True
+
+            self.modified = True
+            self.mtime = st.st_mtime
+
             with open(path) as fp:
-                return self.parse(fp.read())
+                raw_content = fp.read()
+
         except IOError:
             return False
 
+        return self.parse(raw_content)
+
 class TestSuite(object):
+
     def __init__(self, path):
         self.path = path
 
+    def should_generate(self, path):
+        if not os.path.isfile(path):
+            return True
+
+        if any(module.modified for module in self.modules.values()):
+            return True
+
+        return False
+
     def find_modules(self):
         modules = []
         for root, _, files in os.walk(self.path):
@@ -129,15 +156,33 @@ class TestSuite(object):
 
         return modules
 
+    def load_cache(self):
+        path = os.path.join(self.path, '.clarcache')
+        cache = {}
+
+        try:
+            fp = open(path, 'rb')
+            cache = pickle.load(fp)
+            fp.close()
+        except (IOError, ValueError):
+            pass
+
+        return cache
+
+    def save_cache(self):
+        path = os.path.join(self.path, '.clarcache')
+        with open(path, 'wb') as cache:
+            pickle.dump(self.modules, cache)
+
     def load(self, force = False):
         module_data = self.find_modules()
-        self.modules = {}
+        self.modules = {} if force else self.load_cache()
 
         for path, name in module_data:
             if name not in self.modules:
                 self.modules[name] = Module(name)
 
-            if not self.modules[name].load(path):
+            if not self.modules[name].refresh(path):
                 del self.modules[name]
 
     def disable(self, excluded):
@@ -157,6 +202,9 @@ class TestSuite(object):
     def write(self):
         output = os.path.join(self.path, 'clar.suite')
 
+        if not self.should_generate(output):
+            return False
+
         with open(output, 'w') as data:
             for module in self.modules.values():
                 t = Module.DeclarationTemplate(module)
@@ -175,19 +223,22 @@ class TestSuite(object):
             data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count())
             data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count())
 
+        suite.save_cache()
+        return True
+
 if __name__ == '__main__':
     from optparse import OptionParser
 
     parser = OptionParser()
+    parser.add_option('-f', '--force', dest='force', default=False)
     parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[])
 
     options, args = parser.parse_args()
 
     for path in args or ['.']:
         suite = TestSuite(path)
-        suite.load()
+        suite.load(options.force)
         suite.disable(options.excluded)
-        suite.write()
-
-        print("Written `clar.suite` (%d suites)" % len(suite.modules))
+        if suite.write():
+            print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count()))