[the-board/unit-tests] Initial bits for unit tests



commit 6800e81293919d68365c0fddfebe2f20a2d13831
Author: Lucas Rocha <lucasr gnome org>
Date:   Tue Feb 8 17:58:37 2011 +0000

    Initial bits for unit tests

 Makefile.am             |    2 +-
 configure.ac            |    4 +
 test/Makefile.am        |   78 ++++++++++++++++++++++
 test/js/testMathUtil.js |   12 ++++
 test/tb-js-unit.c       |  165 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 260 insertions(+), 1 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 975ac3b..6241857 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
-SUBDIRS = data po src
+SUBDIRS = data po src test
 
 EXTRA_DIST = \
     autogen.sh
diff --git a/configure.ac b/configure.ac
index f4322db..2a9c609 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,9 @@ AC_PROG_LIBTOOL
 ## don't rerun to this point if we abort
 AC_CACHE_SAVE
 
+GJS_JS_DIR=`$PKG_CONFIG --variable=datadir gjs-1.0`/gjs-1.0
+AC_SUBST(GJS_JS_DIR)
+
 CLUTTER_MIN_VERSION=1.6.0
 GLIB_MIN_VERSION=2.27.3
 GTK_MIN_VERSION=2.91.7
@@ -153,6 +156,7 @@ data/icons/Makefile
 data/style/Makefile
 data/things/Makefile
 po/Makefile.in
+test/Makefile
 ])
 
 AC_OUTPUT
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..52acdf9
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,78 @@
+GTESTER = $(TESTS_ENVIRONMENT) gtester
+GTESTER_REPORT = gtester-report
+TEST_PROGS_OPTIONS ?= --keep-going
+
+TEST_PROGS = tb-js-unit
+bin_PROGRAMS = tb-js-unit
+
+tb_js_unit_CPPFLAGS = \
+	-DGJS_JS_DIR=\"$(GJS_JS_DIR)\" \
+	$(AM_CPPFLAGS) \
+	$(THE_BOARD_CFLAGS)
+
+tb_js_unit_LDADD = \
+	$(THE_BOARD_LIBS)
+
+## -rdynamic makes backtraces work
+## we -export-dynamic so we can dlopen ourselves and use gobject-introspection
+tb_js_unit_LDFLAGS=-export-dynamic -rdynamic
+tb_js_unit_SOURCES = tb-js-unit.c
+
+THE_BOARD_GJS_PATH = $(abs_top_builddir)/.libs:$(abs_top_srcdir)/src/js
+
+# Default log output, overrideable from environment, thanks to
+# conditional assignment operator '?=' .
+THE_BOARD_TEST_LOGS_OUTPUT ?= $(builddir)/test_user_data/logs/the-board-%u.log
+
+TESTS_ENVIRONMENT = \
+	DISPLAY='' \
+	XDG_DATA_HOME=$(abs_top_builddir)/test_user_data \
+    GJS_DEBUG_OUTPUT=$(THE_BOARD_TEST_LOGS_OUTPUT) \
+	GI_TYPELIB_PATH=$(abs_top_builddir)/src \
+	JS_TEST_DIR=$(abs_top_builddir)/test/js \ 
+	GJS_PATH=$(THE_BOARD_GJS_PATH)
+
+### gtester testing rules
+
+# run one test only, e.g. test-/js/Array
+test-/%:
+	make test TEST_PROGS_OPTIONS="-p $(@:test-%=%)"
+
+# test: run all tests in cwd
+test: ${TEST_PROGS}
+	@rm -rf test_user_data
+	@mkdir -p test_user_data
+	@test -z "${TEST_PROGS}" || ${GTESTER} --verbose ${TEST_PROGS} ${TEST_PROGS_OPTIONS}
+
+# test-report: run tests in cwd and generate report
+# perf-report: run tests in cwd with -m perf and generate report
+# full-report: like test-report: with -m perf and -m slow
+test-report perf-report full-report: ${TEST_PROGS}
+	@test -z "${TEST_PROGS}" || { \
+	  case $@ in \
+	  test-report) test_options="-k";; \
+	  perf-report) test_options="-k -m=perf";; \
+	  full-report) test_options="-k -m=perf -m=slow";; \
+	  esac ; \
+	  ${GTESTER} --verbose $$test_options -o $  xml ${TEST_PROGS} ${TEST_PROGS_OPTIONS}; \
+	}
+	@${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $  xml >$  html
+
+test-console:
+	@$(TESTS_ENVIRONMENT) rlwrap gjs-console
+
+CLEANFILES = \
+	unittestdb # Remove this when the tests remove the dbs themselves
+
+.PHONY: test test-report perf-report full-report test-coverage
+
+# run make test as part of make check
+check-local: test
+
+clean-local:
+	-rm -rf test-coverage
+	-rm -f *.gcda *.gcno
+	-rm -rf test_user_data
+
+#noinst_jsdirs = \
+#	js
diff --git a/test/js/testMathUtil.js b/test/js/testMathUtil.js
new file mode 100644
index 0000000..4dcc843
--- /dev/null
+++ b/test/js/testMathUtil.js
@@ -0,0 +1,12 @@
+const MathUtil = imports.util.mathUtil;
+
+function testClamp() {
+    assertEquals(5, MathUtil.clamp(7, 0, 5));
+    assertEquals(0, MathUtil.clamp(-3, 0, 5));
+    assertEquals(3, MathUtil.clamp(3, 0, 5));
+    assertEquals(1, MathUtil.clamp(1, 1, 1));
+
+    assertRaises('min greater than max', function() { MathUtil.clamp(0, 5, 0); });
+}
+
+gjstestRun();
diff --git a/test/tb-js-unit.c b/test/tb-js-unit.c
new file mode 100644
index 0000000..580c454
--- /dev/null
+++ b/test/tb-js-unit.c
@@ -0,0 +1,165 @@
+/* Copyright 2008 litl, LLC. All Rights Reserved. */
+
+#include <config.h>
+
+#include <glib.h>
+#include <gjs/gjs.h>
+
+#include <string.h>
+
+typedef struct {
+    GjsContext *context;
+} TbTestJSFixture;
+
+static const char *js_test_dir;
+
+static void
+setup (TbTestJSFixture *fix,
+       gconstpointer    test_data)
+{
+  GError *error = NULL;
+  gboolean success;
+  int code;
+
+  g_debug ("------------------------------");
+  g_debug ("setup gjs test file: %s", (const char*) test_data);
+
+  fix->context = gjs_context_new ();
+
+  /* Load jsUnit.js directly into global scope, rather than
+   * requiring each test to import it as a module, among other
+   * things this lets us test importing modules without relying on
+   * importing a module, but also it's just less typing to have
+   * "assert*" without a prefix.
+   */
+  success = gjs_context_eval_file (fix->context, GJS_JS_DIR"/jsUnit.js", &code, &error);
+
+  if (!success)
+    g_error("%s", error->message);
+}
+
+static void
+teardown (TbTestJSFixture *fix,
+          gconstpointer     test_data)
+{
+  g_debug ("teardown gjs test file: %s", (const char*) test_data);
+
+  gjs_memory_report ("before destroying context", FALSE);
+  g_object_unref (fix->context);
+
+  gjs_memory_report ("after destroying context", TRUE);
+}
+
+static void
+test (TbTestJSFixture *fix,
+      gconstpointer     test_data)
+{
+  char *test_script;
+  GError *error = NULL;
+  gboolean success;
+  int code;
+
+  g_debug ("test gjs test file: %s", (const char*) test_data);
+
+  /* verify that last line of test is either 'gjstestRun();' or 'st;'
+     this ensures that we accurately report the results of the test!
+     otherwise gjstestRun() can fail silently, which is Not Good.
+     Use:
+      let st = gjstestRun();
+      // some other stuff
+      st;
+     if you really want to do cleanup after gjstestRun().
+  */
+  if (!g_file_get_contents (test_data, &test_script, NULL, &error))
+    g_error ("Couldn't read test: %s", (const char *) test_data);
+
+  if (!g_regex_match_simple("(gjstestRun\\s*\\(\\s*\\)|st)\\s*;?\\s*"
+                            "(/[*][^*]*[*]/\\s*)?$",
+                            test_script, 0, 0))
+    g_error("Return value from gjstestRun() may be being ignored! "
+            "The test case should end in 'gjstestRun()' or 'st'.");
+
+  g_free (test_script);
+
+  /* ok, now run the rest. */
+  success = gjs_context_eval_file (fix->context,
+                                   (const char*) test_data,
+                                   &code, &error);
+
+  if (!success)
+    g_error ("%s", error->message);
+
+  g_assert (error == NULL);
+  g_assert_cmpint (code, ==, 0);
+}
+
+static gint
+mystrcmp (gconstpointer a, gconstpointer b)
+{
+  // filenames are not UTF8; we compare using native strcmp order, not
+  // any locale-specific foo.
+  return strcmp(*(char**)a, *(char**)b);
+}
+
+int
+main(int argc, char **argv)
+{
+  GDir *dir;
+  const char *name;
+  GPtrArray *tests;
+  unsigned i;
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_type_init ();
+
+  /* iterate through all 'test*.js' files in $JS_TEST_DIR */
+
+  /* accumulate the results and sort them, so that our test runs
+   * are consistent across machines (otherwise every developer will
+   * run tests in a different order, depending on the whims of their
+   * filesystem. */
+  js_test_dir = g_getenv ("JS_TEST_DIR");
+  dir = g_dir_open (js_test_dir, 0, NULL);
+
+  g_assert (dir != NULL);
+
+  tests = g_ptr_array_new();
+
+  while ((name = g_dir_read_name(dir)) != NULL)
+    {
+      if (!(g_str_has_prefix (name, "test") &&
+            g_str_has_suffix (name, ".js")))
+          continue;
+
+      g_ptr_array_add (tests, g_strdup(name));
+    }
+
+  g_dir_close (dir);
+
+  g_ptr_array_sort (tests, mystrcmp);
+
+  for (i = 0; i < tests->len; i++)
+    {
+      char *name = g_ptr_array_index (tests, i);
+      char *test_name;
+      char *file_name;
+
+      /* pretty print, drop 'test' prefix and '.js' suffix from test name */
+      test_name = g_strconcat ("/js/", name + 4, NULL);
+      test_name[strlen (test_name)-3] = '\0';
+
+      file_name = g_build_filename (js_test_dir, name, NULL);
+
+      g_test_add (test_name, TbTestJSFixture, file_name, setup, test, teardown);
+
+      g_free (test_name);
+      g_free (name);
+
+      /* not freeing file_name as it's needed while running the test */
+    }
+
+  g_ptr_array_free (tests, TRUE);
+
+  return g_test_run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]