[asterisk-commits] mnicholson: branch mnicholson/asttest r167122 - /team/mnicholson/asttest/astt...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Dec 31 19:34:43 CST 2008


Author: mnicholson
Date: Wed Dec 31 19:34:42 2008
New Revision: 167122

URL: http://svn.digium.com/view/asterisk?view=rev&rev=167122
Log:
Added logging and test result analysis.

 * asttest/asttest.c (test_suite_*): renamed test_suite_* functions to ts_*
 * asttest/asttest.c (ts_log, ts_log_va): added
 * asttest/asttest.c (struct test_suite): added FILE *log member
 * asttest/asttest.c (run_test): added test_name paramater and modified to
 process the test result
 * asttest/asttest.c (process_test_result, result_equals): added, used to
 process test results

Modified:
    team/mnicholson/asttest/asttest/asttest.c

Modified: team/mnicholson/asttest/asttest/asttest.c
URL: http://svn.digium.com/view/asterisk/team/mnicholson/asttest/asttest/asttest.c?view=diff&rev=167122&r1=167121&r2=167122
==============================================================================
--- team/mnicholson/asttest/asttest/asttest.c (original)
+++ team/mnicholson/asttest/asttest/asttest.c Wed Dec 31 19:34:42 2008
@@ -37,13 +37,28 @@
 	unsigned int xfail;
 	unsigned int skip;
 	unsigned int total;
+	FILE *log;
 };
 
-void test_suite_init(struct test_suite *ts) {
+int ts_init(struct test_suite *ts, const char *log_file_path) {
 	memset(ts, 0, sizeof(struct test_suite));
-}
-
-void test_suite_print_results(struct test_suite *ts) {
+
+	ts->log = fopen(log_file_path, "w");
+	if (!ts->log) {
+		fprintf(stderr, "Error log file (%s): %s\n", log_file_path, strerror(errno));
+		return 1;
+	}
+
+	return 0;
+}
+
+void ts_cleanup(struct test_suite *ts) {
+	if (ts->log) {
+		fclose(ts->log);
+	}
+}
+
+void ts_print(struct test_suite *ts) {
 	printf("Test results:\n");
 	printf("  tests passed:      %d\n", ts->pass);
 	printf("  test failures:     %d\n", ts->fail);
@@ -53,27 +68,142 @@
 	printf("Total test run:      %d\n", ts->total);
 }
 
-void test_suite_pass(struct test_suite *ts) {
+int ts_log_va(struct test_suite *ts, const char *test_name, const char *fmt, va_list ap) {
+	int res;
+	res = fprintf(ts->log, "%s: ", test_name);
+	res += vfprintf(ts->log, fmt, ap);
+	return res;
+}
+
+int __attribute__((format(printf, 3, 4))) ts_log(struct test_suite *ts, const char *test_name, const char *fmt, ...) {
+	va_list ap;
+	int res;
+	va_start(ap, fmt);
+	res = ts_log_va(ts, test_name, fmt, ap);
+	va_end(ap);
+	return res;
+}
+
+void ts_pass(struct test_suite *ts, const char *test_name) {
 	ts->pass++;
 	ts->total++;
-}
-
-void test_suite_fail(struct test_suite *ts) {
+	
+	ts_log(ts, test_name, "test passed\n");
+}
+
+void ts_fail(struct test_suite *ts, const char *test_name) {
 	ts->fail++;
 	ts->total++;
-}
-
-void test_suite_xfail(struct test_suite *ts) {
+	
+	ts_log(ts, test_name, "test failed\n");
+}
+
+void ts_xfail(struct test_suite *ts, const char *test_name) {
 	ts->xfail++;
 	ts->total++;
-}
-
-void test_suite_skip(struct test_suite *ts) {
+
+	ts_log(ts, test_name, "expected failure\n");
+}
+
+void ts_skip(struct test_suite *ts, const char *test_name) {
 	ts->skip++;
 	ts->total++;
-}
-
-int run_test(struct test_suite *ts, const char *test_dir_path) {
+
+	ts_log(ts, test_name, "test skipped\n");
+}
+
+/*
+ * \brief Check if the given result string equals the string stored at the 
+ * given index.
+ * \param L the lua state to use
+ * \param result_index the index of the result string
+ * \param result_string the result string to check for equality with the string 
+ * at the given index
+ */
+int result_equals(lua_State *L, int result_index, const char *result_string) {
+	int res;
+	lua_pushstring(L, result_string);
+	res = lua_equal(L, -1, result_index);
+	lua_pop(L, 1);
+	return res;
+}
+
+/*
+ * \brief Process the result of a test.
+ * \param ts the current test suite
+ * \param L the lua state the test was run in
+ *
+ * This function expects to be called after luaL_dofile/lua_pcall and will 
+ * analyze the result of running the test.  The testing framework will pass a 
+ * special table containg the test result to lua_error() that is used by this 
+ * function.
+ *
+ * The table is expected in the following format:
+ *
+ * \code
+ * table = {
+ *    result = "pass" or "fail" or "xfail" or "skip";
+ *    reason = nil or "reason string";
+ * }
+ * \endcode
+ */
+void process_test_result(struct test_suite *ts, const char *test_name, lua_State *L) {
+	if (lua_isstring(L, -1)) {
+		/* this is not a test result, log the error */
+		ts_log(ts, test_name, "error: %s\n", lua_tostring(L, -1));
+		lua_pop(L, 1);
+
+		ts_skip(ts, test_name);
+	} else if (lua_type(L, -1) == LUA_TTABLE) {
+		int result_table = lua_gettop(L);
+		int reason_string = 0;
+		int test_result = 0;
+
+		lua_getfield(L, result_table, "reason");
+		if (!lua_isnil(L, -1) && lua_isstring(L, -1))
+			reason_string = lua_gettop(L);
+		else
+			lua_pop(L, 1);
+
+		lua_getfield(L, result_table, "result");
+		if (lua_isnil(L, -1)) {
+			lua_pop(L, 1);
+			ts_log(ts, test_name, "error reading test result\n");
+			ts_skip(ts, test_name);
+		} else {
+			test_result = lua_gettop(L);
+
+			if (reason_string)
+				ts_log(ts, test_name, "%s\n", lua_tostring(L, reason_string));
+
+			if (result_equals(L, test_result, "pass")) {
+				ts_pass(ts, test_name);
+			} else if (result_equals(L, test_result, "fail")) {
+				ts_fail(ts, test_name);
+			} else if (result_equals(L, test_result, "xfail")) {
+				ts_xfail(ts, test_name);
+			} else if (result_equals(L, test_result, "skip")) {
+				ts_skip(ts, test_name);
+			} else {
+				ts_log(ts, test_name, "unknown result '%s'\n", lua_tostring(L, test_result));
+				ts_skip(ts, test_name);
+			}
+		}
+
+		if (reason_string)
+			lua_remove(L, reason_string);
+		if (test_result)
+			lua_remove(L, test_result);
+
+		lua_pop(L, 1);
+	} else {
+		lua_pop(L, 1);
+		ts_log(ts, test_name, "missing test result\n");
+		ts_skip(ts, test_name);
+	}
+}
+
+int run_test(struct test_suite *ts, const char *test_name, const char *test_dir_path) {
 	char test_file_path[1024];
 	lua_State *L = luaL_newstate();
 	if (!L) {
@@ -84,11 +214,15 @@
 	luaL_openlibs(L);
 
 	// TODO load the standard test libraries
-
-	snprintf(test_file_path, sizeof(test_file_path), "%s/test.lua", test_file_path);
+	
+	snprintf(test_file_path, sizeof(test_file_path), "%s/test.lua", test_dir_path);
 	if (luaL_dofile(L, test_file_path)) {
-		// TODO print error message
-		test_suite_skip(ts);
+		process_test_result(ts, test_name, L);
+		lua_close(L);
+		return 1;
+	} else {
+		ts_log(ts, test_name, "test did not return a result\n");
+		ts_skip(ts, test_name);
 		lua_close(L);
 		return 1;
 	}
@@ -129,17 +263,19 @@
 		return 1;
 	}
 
-	test_suite_init(&ts);
+	ts_init(&ts, "asttest.log");
 
 	while ((ent = readdir(main_dir))) {
 		snprintf(full_path, sizeof(full_path), "%s/%s", path, ent->d_name);
 		if (is_directory(full_path) && !ignored_dir(full_path)) {
-			run_test(&ts, full_path);
+			run_test(&ts, ent->d_name, full_path);
 		}
 	}
 	closedir(main_dir);
 
-	test_suite_print_results(&ts);
+	ts_print(&ts);
+
+	ts_cleanup(&ts);
 	return 0;
 }
 
@@ -155,5 +291,7 @@
 		return 1;
 	}
 
+	// TODO process args and except --log (-l) as an argument for where to log
+
 	return process_tests_in_dir(argv[1]);
 }




More information about the asterisk-commits mailing list