diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am index 75da2add9..73d24eb3d 100644 --- a/tests/interactive/Makefile.am +++ b/tests/interactive/Makefile.am @@ -74,11 +74,13 @@ endif # For convenience, this provides a way to easily run individual unit tests: wrappers: stamp-test-interactive @true -stamp-test-interactive: Makefile test-interactive$(EXEEXT) +stamp-test-interactive: Makefile @wrapper=$(abs_builddir)/wrapper.sh ; \ chmod +x $$wrapper && \ ( echo "/stamp-test-interactive" ; \ + echo "/stamp-test-unit-names" ; \ echo "/test-interactive" ; \ + echo "/test-unit-names.h" ; \ echo "*.o" ; \ echo ".gitignore" ) > .gitignore ; \ for i in $(UNIT_TESTS); \ @@ -93,6 +95,21 @@ stamp-test-interactive: Makefile test-interactive$(EXEEXT) done \ && echo timestamp > $(@F) +test-unit-names.h: stamp-test-unit-names + @true + +stamp-test-unit-names: Makefile + @( echo "/* ** This file is autogenerated. Do not edit. ** */" ; \ + echo "" ; \ + echo "const char *test_unit_names[] = {" ) > test-unit-names.h ; \ + for i in $(UNIT_TESTS); \ + do \ + test_bin=$${i%*.c} ; \ + echo " \"$$test_bin\"," >> test-unit-names.h ; \ + done \ + && echo "};" >> test-unit-names.h \ + && echo timestamp > $(@F) + clean-wrappers: @for i in $(UNIT_TESTS); \ do \ @@ -115,7 +132,7 @@ common_ldadd = $(top_builddir)/clutter/libclutter-@CLUTTER_SONAME_INFIX@-@CLUTTE noinst_PROGRAMS = test-interactive -test_interactive_SOURCES = test-main.c $(UNIT_TESTS) +test_interactive_SOURCES = test-main.c test-unit-names.h $(UNIT_TESTS) test_interactive_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) test_interactive_CPPFLAGS = \ -DTESTS_DATADIR=\""$(abs_top_srcdir)/tests/data"\" \ @@ -126,8 +143,8 @@ test_interactive_LDFLAGS = -export-dynamic test_interactive_LDADD = $(CLUTTER_LIBS) $(common_ldadd) -lm EXTRA_DIST = wrapper.sh.in -DISTCLEANFILES = wrapper.sh .gitignore +DISTCLEANFILES = wrapper.sh .gitignore test-unit-names.h -BUILT_SOURCES = wrappers +BUILT_SOURCES = wrappers test-unit-names.h clean-local: clean-wrappers diff --git a/tests/interactive/test-main.c b/tests/interactive/test-main.c index 2a0cd74a5..10d032233 100644 --- a/tests/interactive/test-main.c +++ b/tests/interactive/test-main.c @@ -1,37 +1,207 @@ +#include +#include #include #include +#include "test-unit-names.h" + +#define MAX_DESC_SIZE 72 + +static GModule *module = NULL; + +static gpointer +get_symbol_with_suffix (const char *unit_name, + const char *suffix) +{ + char *main_symbol_name; + gpointer func; + + main_symbol_name = g_strconcat (unit_name, "_", suffix, NULL); + main_symbol_name = g_strdelimit (main_symbol_name, "-", '_'); + + g_module_symbol (module, main_symbol_name, &func); + + g_free (main_symbol_name); + + return func; +} + +static gpointer +get_unit_name_main (const char *unit_name) +{ + return get_symbol_with_suffix (unit_name, "main"); +} +static char * +get_unit_name_description (const char *unit_name, + gssize max_len) +{ + const char *description; + gpointer func; + char *retval; + + func = get_symbol_with_suffix (unit_name, "describe"); + if (func == NULL) + description = "No description found"; + else + { + const char *(* unit_test_describe) (void); + + unit_test_describe = func; + + description = unit_test_describe (); + } + + if (max_len > 0 && strlen (description) >= max_len) + { + GString *buf = g_string_sized_new (max_len); + char *newline; + + newline = strchr (description, '\n'); + if (newline != NULL) + { + g_string_append_len (buf, description, + MIN (newline - description - 1, max_len - 3)); + } + else + g_string_append_len (buf, description, max_len - 3); + + g_string_append (buf, "..."); + + retval = g_string_free (buf, FALSE); + } + else + retval = g_strdup (description); + + return retval; +} + +static gboolean list_all = FALSE; +static gboolean describe = FALSE; +static char **unit_names = NULL; + +static GOptionEntry entries[] = { + { + "describe", 'd', + 0, + G_OPTION_ARG_NONE, &describe, + "Describe the interactive unit test", NULL, + }, + { + "list-all", 'l', + 0, + G_OPTION_ARG_NONE, &list_all, + "List all available units", NULL, + }, + { + G_OPTION_REMAINING, 0, + 0, + G_OPTION_ARG_STRING_ARRAY, &unit_names, + "The interactive unit test", "UNIT_NAME" + }, + { NULL } +}; int main (int argc, char **argv) { - GModule *module; - char *unit_test; - char *main_symbol_name; - gpointer func; - int (*unit_test_main) (int argc, char **argv); - int ret; + int ret, i, n_unit_names; + GOptionContext *context; + + context = g_option_context_new (" - Interactive test suite"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_set_help_enabled (context, TRUE); + g_option_context_set_ignore_unknown_options (context, TRUE); + if (!g_option_context_parse (context, &argc, &argv, NULL)) + { + g_print ("Usage: test-interactive \n"); + return EXIT_FAILURE; + } + + g_option_context_free (context); - if (argc < 2) - g_error ("Usage: %s unit_test", argv[0]); - module = g_module_open (NULL, 0); if (!module) - g_error ("Failed to open self for symbol lookup"); + g_error ("*** Failed to open self for symbol lookup"); - unit_test = g_path_get_basename (argv[1]); + ret = EXIT_SUCCESS; - main_symbol_name = g_strdup_printf ("%s_main", unit_test); - main_symbol_name = g_strdelimit (main_symbol_name, "-", '_'); + if (list_all) + { + g_print ("* Available unit tests:\n"); - if (!g_module_symbol (module, main_symbol_name, &func)) - g_error ("Failed to look up main symbol for the test: %s", unit_test); + for (i = 0; i < G_N_ELEMENTS (test_unit_names); i++) + { + char *str; + gsize len; - unit_test_main = func; - ret = unit_test_main (argc - 1, argv + 1); - - g_free (unit_test); - g_free (main_symbol_name); + len = MAX_DESC_SIZE - strlen (test_unit_names[i]); + str = get_unit_name_description (test_unit_names[i], len - 2); + + g_print (" - %s:%*s%s\n", + test_unit_names[i], + (int) len - strlen (str), " ", + str); + + g_free (str); + } + + ret = EXIT_SUCCESS; + goto out; + } + + n_unit_names = g_strv_length (unit_names); + for (i = 0; i < n_unit_names; i++) + { + const char *unit_name = unit_names[i]; + char *unit_test = NULL; + gboolean found; + int j; + + unit_test = g_path_get_basename (unit_name); + + found = FALSE; + for (j = 0; j < G_N_ELEMENTS (test_unit_names); j++) + { + if (strcmp (test_unit_names[j], unit_test) == 0) + { + found = TRUE; + break; + } + } + + if (!found) + g_error ("*** Unit '%s' does not exist", unit_test); + + if (describe) + { + char *str; + + str = get_unit_name_description (unit_test, -1); + + g_print ("* %s:\n%s\n\n", unit_test, str); + + g_free (str); + + ret = EXIT_SUCCESS; + } + else + { + int (* unit_test_main) (int argc, char **argv); + gpointer func; + + func = get_unit_name_main (unit_test); + if (func == NULL) + g_error ("*** Unable to find the main entry point for '%s'", unit_test); + + unit_test_main = func; + + ret = unit_test_main (argc, argv); + } + + g_free (unit_test); + } + +out: g_module_close (module); return ret;