From b1af9da7c54d1a5ae2e5f17689cfac15bb316ba6 Mon Sep 17 00:00:00 2001 From: Sam Spilsbury Date: Fri, 17 Jan 2014 17:56:59 -0200 Subject: Enable coverage report for Gjs Pass --enable-coverage to configure.ac and use "make lcov" to generate an lcov HTML report using both the JS coverage tools and gcov. --- Makefile-test.am | 54 ++++++++++++++++++++++ installed-tests/gjs-unit.cpp | 108 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 154 insertions(+), 8 deletions(-) diff --git a/Makefile-test.am b/Makefile-test.am index 52a12352..593ea048 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -39,6 +39,8 @@ gjs_tests_SOURCES = \ check-local: gjs-tests @test -z "${TEST_PROGS}" || ${GTESTER} --verbose ${TEST_PROGS} ${TEST_PROGS_OPTIONS} +# GJS_PATH is empty here since we want to force the use of our own +# resources TESTS_ENVIRONMENT = \ TOP_SRCDIR=$(top_srcdir) \ DBUS_SESSION_BUS_ADDRESS='' \ @@ -47,6 +49,58 @@ TESTS_ENVIRONMENT = \ BUILDDIR=. \ GJS_USE_UNINSTALLED_FILES=1 \ GJS_TEST_TIMEOUT=420 \ + GJS_PATH= \ GI_TYPELIB_PATH=$(builddir):$(GI_TYPELIB_PATH) \ LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):$(FIREFOX_JS_LIBDIR)" \ G_FILENAME_ENCODING=latin1 # ensure filenames are not utf8 + +if ENABLE_COVERAGE +# These paths are resource paths but they have resource:// +# stripped out, for ease of parsing in the test runner +coverage_paths = \ + /org/gnome/gjs/modules/cairo.js \ + /org/gnome/gjs/modules/coverage.js \ + /org/gnome/gjs/modules/format.js \ + /org/gnome/gjs/modules/gettext.js \ + /org/gnome/gjs/modules/jsUnit.js \ + /org/gnome/gjs/modules/lang.js \ + /org/gnome/gjs/modules/mainloop.js \ + /org/gnome/gjs/modules/signals.js + +empty := +space := $(empty) $(empty) +colon := : + +coverage_env := $(subst $(space),$(colon),$(coverage_paths)) + +TESTS_ENVIRONMENT += \ + GJS_UNIT_COVERAGE_OUTPUT=lcov \ + GJS_UNIT_COVERAGE_PATHS=$(coverage_env) +endif + +######################################################################## +if ENABLE_COVERAGE +lcov: + test -d lcov || mkdir lcov + $(LCOV) --compat-libtool --directory . --capture -o lcov/lcov_tmp.info + $(LCOV) --extract lcov/lcov_tmp.info "$(PWD)/*" -o lcov/lcov.info + rm -f lcov/lcov_tmp.info + $(GENHTML) --legend -o lcov lcov/lcov.info lcov/coverage.lcov + +lcov-clean: + find . -name '*.gcda' -delete + rm -rf lcov + +lcov-realclean: lcov-clean + find . -name '*.gcno' -delete + +clean-local: lcov-realclean + +.PHONY: lcov lcov-clean lcov-realclean +else +lcov: + @echo >&1 "*** ERROR: 'configure --enable-coverage' required" + @exit 1 + +.PHONY: lcov +endif diff --git a/installed-tests/gjs-unit.cpp b/installed-tests/gjs-unit.cpp index 69fc4d09..9f58cee3 100644 --- a/installed-tests/gjs-unit.cpp +++ b/installed-tests/gjs-unit.cpp @@ -27,25 +27,72 @@ #include #include #include +#include #include #include typedef struct { - GjsContext *context; + const char **coverage_paths; + const char *coverage_output_path; + char *filename; +} GjsTestData; + +GjsTestData * +gjs_unit_test_data_new(const char **coverage_paths, + const char *coverage_output_path, + char *filename) +{ + GjsTestData *data = (GjsTestData *) g_new0(GjsTestData, 1); + data->coverage_paths = coverage_paths; + data->coverage_output_path = coverage_output_path; + data->filename = filename; + return data; +} + +void +gjs_unit_test_data_free(gpointer test_data, gpointer user_data) +{ + GjsTestData *data = (GjsTestData *) test_data; + g_free(data->filename); + g_free(data); +} + +typedef struct { + GjsContext *context; + GjsCoverage *coverage; } GjsTestJSFixture; static void setup(GjsTestJSFixture *fix, gconstpointer test_data) { + GjsTestData *data = (GjsTestData *) test_data; fix->context = gjs_context_new (); + + if (data->coverage_paths) { + if (!data->coverage_output_path) { + g_error("GJS_UNIT_COVERAGE_OUTPUT is required when using GJS_UNIT_COVERAGE_PATHS"); + } + + fix->coverage = gjs_coverage_new((const char **) data->coverage_paths, + fix->context); + } } static void teardown(GjsTestJSFixture *fix, gconstpointer test_data) { + GjsTestData *data = (GjsTestData *) test_data; + + if (fix->coverage) { + gjs_coverage_write_statistics(fix->coverage, + data->coverage_output_path); + + g_clear_object(&fix->coverage); + } + gjs_memory_report("before destroying context", FALSE); g_object_unref(fix->context); gjs_memory_report("after destroying context", TRUE); @@ -59,7 +106,9 @@ test(GjsTestJSFixture *fix, gboolean success; int code; - success = gjs_context_eval_file(fix->context, (const char*)test_data, &code, &error); + GjsTestData *data = (GjsTestData *) test_data; + + success = gjs_context_eval_file(fix->context, data->filename, &code, &error); if (!success) g_error("%s", error->message); g_assert(error == NULL); @@ -85,12 +134,42 @@ read_all_dir_sorted (const char *dirpath) return result; } +static char ** +get_coverage_uris_from_env(const char *key) +{ + const char *value = g_getenv(key); + + if (!value) + return NULL; + + char **splitted_pathnames = g_strsplit(value, ":", -1); + char **splitted_pathnamed_iterator = splitted_pathnames; + + for (; *splitted_pathnamed_iterator; splitted_pathnamed_iterator++) { + + /* Don't just have resource:// for the last element */ + if (g_strcmp0(*splitted_pathnamed_iterator, "") == 0) { + g_free(*splitted_pathnamed_iterator); + *splitted_pathnamed_iterator = NULL; + continue; + } + + char *uri = g_strconcat("resource://", + *splitted_pathnamed_iterator, + NULL); + g_free(*splitted_pathnamed_iterator); + *splitted_pathnamed_iterator = uri; + } + + return splitted_pathnames; +} + int main(int argc, char **argv) { char *js_test_dir; GSList *all_tests, *iter; - GSList *test_filenames = NULL; + GSList *all_registered_test_data = NULL; int retval; /* The tests are known to fail in the presence of the JIT; @@ -112,11 +191,15 @@ main(int argc, char **argv) js_test_dir = g_build_filename(INSTTESTDIR, "js", NULL); } + char **coverage_paths = get_coverage_uris_from_env("GJS_UNIT_COVERAGE_PATHS"); + const char *coverage_output_directory = g_getenv("GJS_UNIT_COVERAGE_OUTPUT"); + all_tests = read_all_dir_sorted(js_test_dir); for (iter = all_tests; iter; iter = iter->next) { char *name = (char*) iter->data; char *test_name; char *file_name; + GjsTestData *test_data; if (!(g_str_has_prefix(name, "test") && g_str_has_suffix(name, ".js"))) { @@ -131,17 +214,26 @@ main(int argc, char **argv) test_name[strlen(test_name)-3] = '\0'; file_name = g_build_filename(js_test_dir, name, NULL); - g_test_add(test_name, GjsTestJSFixture, file_name, setup, test, teardown); + test_data = gjs_unit_test_data_new((const char **) coverage_paths, + coverage_output_directory, + file_name); + g_test_add(test_name, GjsTestJSFixture, test_data, setup, test, teardown); g_free(name); g_free(test_name); - test_filenames = g_slist_prepend(test_filenames, file_name); - /* not freeing file_name yet as it's needed while running the test */ + all_registered_test_data = g_slist_prepend(all_registered_test_data, test_data); + /* not freeing file_name or test_data yet as it's needed while running the test */ } g_free(js_test_dir); g_slist_free(all_tests); retval = g_test_run (); - g_slist_foreach(test_filenames, (GFunc)g_free, test_filenames); - g_slist_free(test_filenames); + g_slist_foreach(all_registered_test_data, + (GFunc)gjs_unit_test_data_free, + all_registered_test_data); + g_slist_free(all_registered_test_data); + + if (coverage_paths) + g_strfreev(coverage_paths); + return retval; } -- cgit v1.2.1