diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/Makefile.in | 24 | ||||
| -rw-r--r-- | include/gsystem-local-alloc.h | 57 | ||||
| -rw-r--r-- | include/nm-test-utils.h | 246 | ||||
| -rw-r--r-- | include/nm-utils-internal.h | 73 |
4 files changed, 344 insertions, 56 deletions
diff --git a/include/Makefile.in b/include/Makefile.in index 07ade2fb..016710b6 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -78,7 +88,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = include -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -119,6 +129,7 @@ am__can_run_installinfo = \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -145,7 +156,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -180,6 +190,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -404,7 +415,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu include/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -580,6 +590,8 @@ uninstall-am: mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/include/gsystem-local-alloc.h b/include/gsystem-local-alloc.h index 68b12274..51b62519 100644 --- a/include/gsystem-local-alloc.h +++ b/include/gsystem-local-alloc.h @@ -43,22 +43,6 @@ G_BEGIN_DECLS * 1) Take a pointer to the location (typically itself a pointer). * 2) Provide %NULL-safety where it doesn't exist already (e.g. g_object_unref) */ -GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free) -GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_keyfile_unref, g_key_file_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free) -GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref) -GS_DEFINE_CLEANUP_FUNCTION(GList*, gs_local_free_list, g_list_free) -GS_DEFINE_CLEANUP_FUNCTION(GSList*, gs_local_free_slist, g_slist_free) -GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariant*, gs_local_variant_unref, g_variant_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant_iter_free) - -GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev) -GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) /** * gs_free: @@ -66,6 +50,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * Call g_free() on a variable location when it goes out of scope. */ #define gs_free __attribute__ ((cleanup(gs_local_free))) +GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) /** * gs_unref_object: @@ -75,6 +60,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * %NULL. */ #define gs_unref_object __attribute__ ((cleanup(gs_local_obj_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref) /** * gs_unref_variant: @@ -84,6 +70,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * %NULL. */ #define gs_unref_variant __attribute__ ((cleanup(gs_local_variant_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariant*, gs_local_variant_unref, g_variant_unref) /** * gs_free_variant_iter: @@ -92,6 +79,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * scope. */ #define gs_free_variant_iter __attribute__ ((cleanup(gs_local_variant_iter_free))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant_iter_free) /** * gs_free_variant_builder: @@ -100,6 +88,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * scope. */ #define gs_unref_variant_builder __attribute__ ((cleanup(gs_local_variant_builder_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref) /** * gs_unref_array: @@ -110,6 +99,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) */ #define gs_unref_array __attribute__ ((cleanup(gs_local_array_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref) /** * gs_unref_ptrarray: @@ -120,6 +110,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) */ #define gs_unref_ptrarray __attribute__ ((cleanup(gs_local_ptrarray_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref) /** * gs_unref_hashtable: @@ -129,6 +120,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * be %NULL. */ #define gs_unref_hashtable __attribute__ ((cleanup(gs_local_hashtable_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref) /** * gs_free_list: @@ -137,6 +129,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * of scope. */ #define gs_free_list __attribute__ ((cleanup(gs_local_free_list))) +GS_DEFINE_CLEANUP_FUNCTION(GList*, gs_local_free_list, g_list_free) /** * gs_free_slist: @@ -145,6 +138,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * of scope. */ #define gs_free_slist __attribute__ ((cleanup(gs_local_free_slist))) +GS_DEFINE_CLEANUP_FUNCTION(GSList*, gs_local_free_slist, g_slist_free) /** * gs_free_checksum: @@ -154,6 +148,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * be %NULL. */ #define gs_free_checksum __attribute__ ((cleanup(gs_local_checksum_free))) +GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free) /** * gs_unref_bytes: @@ -163,6 +158,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * be %NULL. */ #define gs_unref_bytes __attribute__ ((cleanup(gs_local_bytes_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref) /** * gs_strfreev: @@ -170,6 +166,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * Call g_strfreev() on a variable location when it goes out of scope. */ #define gs_strfreev __attribute__ ((cleanup(gs_local_strfreev))) +GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev) /** * gs_free_error: @@ -177,6 +174,34 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) * Call g_error_free() on a variable location when it goes out of scope. */ #define gs_free_error __attribute__ ((cleanup(gs_local_free_error))) +GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free) + +/** + * gs_unref_keyfile: + * + * Call g_key_file_unref() on a variable location when it goes out of scope. + */ +#define gs_unref_keyfile __attribute__ ((cleanup(gs_local_keyfile_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_keyfile_unref, g_key_file_unref) + +static inline void +gs_cleanup_close_fdp (int *fdp) +{ + int fd; + + g_assert (fdp); + + fd = *fdp; + if (fd != -1) + (void) close (fd); +} + +/** + * gs_fd_close: + * + * Call close() on a variable location when it goes out of scope. + */ +#define gs_fd_close __attribute__((cleanup(gs_cleanup_close_fdp))) G_END_DECLS diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h index dcfa46eb..5f83d09d 100644 --- a/include/nm-test-utils.h +++ b/include/nm-test-utils.h @@ -21,6 +21,66 @@ #ifndef __NM_TEST_UTILS_H__ #define __NM_TEST_UTILS_H__ +/******************************************************************************* + * HOWTO run tests. + * + * Our tests (make check) include this header-only file nm-test-utils.h. + * + * Logging: + * In tests, nm-logging redirects to glib logging. By default, glib suppresses all debug + * messages unless you set G_MESSAGES_DEBUG. To enable debug logging, you can explicitly set + * G_MESSAGES_DEBUG. Otherwise, nm-test will set G_MESSAGES_DEBUG=all in debug mode (see below). + * For nm-logging, you can configure the log-level and domains via NMTST_DEBUG environment + * variable. + * + * Assert-logging: + * Some tests assert against logged messages (g_test_expect_message()). + * By specifying no-expect-message in NMTST_DEBUG, you can disable assert logging + * and g_test_assert_expected_messages() will not fail. + * + * NMTST_SEED_RAND environment variable: + * Tests that use random numbers from nmtst_get_rand() get seeded randomly at each start. + * You can specify the seed by setting NMTST_SEED_RAND. Also, tests will print the seed + * to stdout, so that you know the choosen seed. + * + * + * NMTST_DEBUG environment variable: + * + * "debug", "no-debug": when at test is run in debug mode, it might behave differently, + * depending on the test. See nmtst_is_debug(). + * Known differences: + * - a test might leave the logging level unspecified. In this case, running in + * debug mode, will turn on DEBUG logging, otherwise WARN logging only. + * - if G_MESSAGES_DEBUG is unset, nm-test will set G_MESSAGES_DEBUG=all + * for tests that don't do assert-logging. + * Debug mode is determined as follows (highest priority first): + * - command line option --debug/--no-debug + * - NMTST_DEBUG=debug/no-debug + * - setting NMTST_DEBUG implies debugging turned on + * - g_test_verbose() + * + * "no-expect-message": for tests that would assert against log messages, disable + * those asserts. + * + * "log-level=LEVEL", "log-domains=DOMAIN": reset the log level and domain for tests. + * It only has an effect for nm-logging messages. + * This has no effect if the test asserts against logging (unless no-expect-message), + * otherwise, changing the logging would break tests. + * If you set the level to DEBUG or TRACE, it also sets G_MESSAGES_DEBUG=all (unless + * in assert-logging mode and unless G_MESSAGES_DEBUG is already defined). + * + * "sudo-cmd=PATH": when running root tests as normal user, the test will execute + * itself by invoking sudo at PATH. + * For example + * NMTST_DEBUG="sudo-cmd=$PWD/tools/test-sudo-wrapper.sh" make -C src/platform/tests/ check + * + * "slow|quick|thorough": enable/disable long-running tests. This sets nmtst_test_quick(). + * Whether long-running tests are enabled is determined as follows (highest priority first): + * - specifying the value in NMTST_DEBUG has highest priority + * - respect g_test_quick(), if the command line contains '-mslow', '-mquick', '-mthorough'. + * - use compile time default + * + *******************************************************************************/ #include <arpa/inet.h> #include <stdio.h> @@ -32,10 +92,14 @@ #include <errno.h> #include "nm-utils.h" +#include "nm-utils-internal.h" #include "nm-glib-compat.h" #include "gsystem-local-alloc.h" +/* Analog to EXIT_SUCCESS and EXIT_FAILURE. */ +#define EXIT_SKIP (77) + /*******************************************************************************/ /* general purpose functions that have no dependency on other nmtst functions */ @@ -68,6 +132,7 @@ struct __nmtst_internal gboolean is_debug; gboolean assert_logging; gboolean no_expect_message; + gboolean test_quick; char *sudo_cmd; char **orig_argv; }; @@ -75,7 +140,15 @@ struct __nmtst_internal extern struct __nmtst_internal __nmtst_internal; #define NMTST_DEFINE() \ - struct __nmtst_internal __nmtst_internal = { 0 }; +struct __nmtst_internal __nmtst_internal = { 0 }; \ +\ +__attribute__ ((destructor)) static void \ +_nmtst_exit (void) \ +{ \ + __nmtst_internal.assert_logging = FALSE; \ + g_test_assert_expected_messages (); \ + nmtst_free (); \ +} inline static gboolean @@ -84,13 +157,13 @@ nmtst_initialized (void) return !!__nmtst_internal.rand0; } -#define __NMTST_LOG(cmd, fmt, ...) \ +#define __NMTST_LOG(cmd, ...) \ G_STMT_START { \ g_assert (nmtst_initialized ()); \ if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) { \ - cmd (fmt, __VA_ARGS__); \ + cmd (__VA_ARGS__); \ } else { \ - printf (fmt "\n", __VA_ARGS__); \ + printf (_NM_UTILS_MACRO_FIRST (__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END @@ -161,9 +234,8 @@ nmtst_free (void) } inline static void -__nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_level, const char *log_domains) +__nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_level, const char *log_domains, gboolean *out_set_logging) { - static gsize atexit_registered = 0; const char *nmtst_debug; gboolean is_debug = FALSE; char *c_log_level = NULL, *c_log_domains = NULL; @@ -171,6 +243,14 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ GArray *debug_messages = g_array_new (TRUE, FALSE, sizeof (char *)); int i; gboolean no_expect_message = FALSE; + gboolean _out_set_logging; + gboolean test_quick = FALSE; + gboolean test_quick_set = FALSE; + gboolean test_quick_argv = FALSE; + + if (!out_set_logging) + out_set_logging = &_out_set_logging; + *out_set_logging = FALSE; g_assert (!nmtst_initialized ()); @@ -231,6 +311,12 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ sudo_cmd = g_strdup (&debug[strlen ("sudo-cmd=")]); } else if (!g_ascii_strcasecmp (debug, "no-expect-message")) { no_expect_message = TRUE; + } else if (!g_ascii_strcasecmp (debug, "slow") || !g_ascii_strcasecmp (debug, "thorough")) { + test_quick = FALSE; + test_quick_set = TRUE; + } else if (!g_ascii_strcasecmp (debug, "quick")) { + test_quick = TRUE; + test_quick_set = TRUE; } else { char *msg = g_strdup_printf (">>> nmtst: ignore unrecognized NMTST_DEBUG option \"%s\"", debug); @@ -242,15 +328,35 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ g_free (nmtst_debug_copy); } - if (argv && *argv) { - char **a = *argv; + if (__nmtst_internal.orig_argv) { + char **a = __nmtst_internal.orig_argv; - for (; *a; a++) { + for (; *a; a++) { if (!g_ascii_strcasecmp (*a, "--debug")) is_debug = TRUE; else if (!g_ascii_strcasecmp (*a, "--no-debug")) is_debug = FALSE; - } + else if ( !strcmp (*a, "-m=slow") + || !strcmp (*a, "-m=thorough") + || !strcmp (*a, "-m=quick") + || (!strcmp (*a, "-m") && *(a+1) + && ( !strcmp (*(a+1), "quick") + || !strcmp (*(a+1), "slow") + || !strcmp (*(a+1), "thorough")))) + test_quick_argv = TRUE; + } + } + + if (test_quick_set) + __nmtst_internal.test_quick = test_quick; + else if (test_quick_argv) + __nmtst_internal.test_quick = g_test_quick (); + else { +#ifdef NMTST_TEST_QUICK + __nmtst_internal.test_quick = NMTST_TEST_QUICK; +#else + __nmtst_internal.test_quick = FALSE; +#endif } __nmtst_internal.is_debug = is_debug; @@ -268,6 +374,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ gboolean success = TRUE; #ifdef __NETWORKMANAGER_LOGGING_H__ success = nm_logging_setup (log_level, log_domains, NULL, NULL); + *out_set_logging = TRUE; #endif g_assert (success); } else if (__nmtst_internal.no_expect_message) { @@ -275,6 +382,19 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ * This transforms g_test_expect_message() into a NOP, but we also have to relax * g_log_set_always_fatal(), which was set by g_test_init(). */ g_log_set_always_fatal (G_LOG_FATAL_MASK); +#ifdef __NETWORKMANAGER_LOGGING_H__ + if (c_log_domains || c_log_level) { + /* Normally, tests with assert_logging do not overwrite the logging level/domains because + * the logging statements are part of the assertions. But if the test is run with + * no-expect-message *and* the logging is set explicitly via environment variables, + * we still reset the logging. */ + gboolean success; + + success = nm_logging_setup (log_level, log_domains, NULL, NULL); + *out_set_logging = TRUE; + g_assert (success); + } +#endif } else { #if GLIB_CHECK_VERSION(2,34,0) /* We were called not to set logging levels. This means, that the user @@ -287,7 +407,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ } if ((!__nmtst_internal.assert_logging || (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)) && - (is_debug || (log_level && !g_ascii_strcasecmp (log_level, "DEBUG"))) && + (is_debug || (c_log_level && (!g_ascii_strcasecmp (c_log_level, "DEBUG") || !g_ascii_strcasecmp (c_log_level, "TRACE")))) && !g_getenv ("G_MESSAGES_DEBUG")) { /* if we are @is_debug or @log_level=="DEBUG" and @@ -307,11 +427,6 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ g_free (c_log_level); g_free (c_log_domains); - if (g_once_init_enter (&atexit_registered)) { - atexit (nmtst_free); - g_once_init_leave (&atexit_registered, 1); - } - #ifdef __NETWORKMANAGER_UTILS_H__ /* ensure that monotonic timestamp is called (because it initially logs a line) */ nm_utils_get_monotonic_timestamp_s (); @@ -322,18 +437,27 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ inline static void nmtst_init_with_logging (int *argc, char ***argv, const char *log_level, const char *log_domains) { - __nmtst_init (argc, argv, FALSE, log_level, log_domains); + __nmtst_init (argc, argv, FALSE, log_level, log_domains, NULL); } inline static void -nmtst_init_assert_logging (int *argc, char ***argv) +nmtst_init_assert_logging (int *argc, char ***argv, const char *log_level, const char *log_domains) { - __nmtst_init (argc, argv, TRUE, NULL, NULL); + gboolean set_logging; + + __nmtst_init (argc, argv, TRUE, NULL, NULL, &set_logging); + + if (!set_logging) { + gboolean success; + + success = nm_logging_setup (log_level, log_domains, NULL, NULL); + g_assert (success); + } } #else inline static void nmtst_init (int *argc, char ***argv, gboolean assert_logging) { - __nmtst_init (argc, argv, assert_logging, NULL, NULL); + __nmtst_init (argc, argv, assert_logging, NULL, NULL, NULL); } #endif @@ -344,19 +468,42 @@ nmtst_is_debug (void) return __nmtst_internal.is_debug; } +inline static gboolean +nmtst_test_quick (void) +{ + g_assert (nmtst_initialized ()); + return __nmtst_internal.test_quick; +} + #if GLIB_CHECK_VERSION(2,34,0) #undef g_test_expect_message #define g_test_expect_message(...) \ G_STMT_START { \ g_assert (nmtst_initialized ()); \ if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \ - g_debug ("nmtst: swallow g_test_expect_message %s", G_STRINGIFY ((__VA_ARGS__))); \ + g_debug ("nmtst: assert-logging: g_test_expect_message %s", G_STRINGIFY ((__VA_ARGS__))); \ } else { \ G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ g_test_expect_message (__VA_ARGS__); \ G_GNUC_END_IGNORE_DEPRECATIONS \ } \ } G_STMT_END +#undef g_test_assert_expected_messages_internal +#define g_test_assert_expected_messages_internal(domain, file, line, func) \ + G_STMT_START { \ + const char *_domain = (domain); \ + const char *_file = (file); \ + const char *_func = (func); \ + int _line = (line); \ + \ + g_assert (nmtst_initialized ()); \ + if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) \ + g_debug ("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", _domain?:"", _file?:"", _line, _func?:""); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_test_assert_expected_messages_internal (_domain, _file, _line, _func); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } G_STMT_END #endif inline static GRand * @@ -380,7 +527,7 @@ nmtst_get_rand (void) gint64 i; i = g_ascii_strtoll (str, &s, 0); - g_assert (s[0] == '\0' && i >= 0 && i < G_MAXINT32); + g_assert (s[0] == '\0' && i >= 0 && i < G_MAXUINT32); seed = i; __nmtst_internal.rand = g_rand_new_with_seed (seed); @@ -392,7 +539,7 @@ nmtst_get_rand (void) } __nmtst_internal.rand_seed = seed; - __NMTST_LOG (g_message, ">> initialize nmtst_get_rand() with seed=%u", seed); + g_print ("\nnmtst: initialize nmtst_get_rand() with NMTST_SEED_RAND=%u\n", seed); } return __nmtst_internal.rand; } @@ -623,14 +770,28 @@ nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gate return route; } +inline static int +_nmtst_platform_ip4_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return nm_platform_ip4_route_cmp ((const NMPlatformIP4Route *) a, (const NMPlatformIP4Route *) b); +} + inline static void -nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gsize len) +nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order) { gsize i; + gs_free const NMPlatformIP4Route *c_a = NULL, *c_b = NULL; g_assert (a); g_assert (b); + if (ignore_order) { + a = c_a = g_memdup (a, sizeof (NMPlatformIP4Route) * len); + b = c_b = g_memdup (b, sizeof (NMPlatformIP4Route) * len); + g_qsort_with_data (c_a, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL); + g_qsort_with_data (c_b, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL); + } + for (i = 0; i < len; i++) { if (nm_platform_ip4_route_cmp (&a[i], &b[i]) != 0) { g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (long unsigned) i, @@ -644,14 +805,28 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP } } +inline static int +_nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return nm_platform_ip6_route_cmp ((const NMPlatformIP6Route *) a, (const NMPlatformIP6Route *) b); +} + inline static void -nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gsize len) +nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order) { gsize i; + gs_free const NMPlatformIP6Route *c_a = NULL, *c_b = NULL; g_assert (a); g_assert (b); + if (ignore_order) { + a = c_a = g_memdup (a, sizeof (NMPlatformIP6Route) * len); + b = c_b = g_memdup (b, sizeof (NMPlatformIP6Route) * len); + g_qsort_with_data (c_a, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL); + g_qsort_with_data (c_b, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL); + } + for (i = 0; i < len; i++) { if (nm_platform_ip6_route_cmp (&a[i], &b[i]) != 0) { g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (long unsigned) i, @@ -824,18 +999,21 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect b = b2 = nmtst_connection_duplicate_and_normalize (b); compare = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings); - if (!compare && out_settings) { + if (!compare || out_settings) { const char *name, *pname; GHashTable *setting; GHashTableIter iter, iter2; - g_hash_table_iter_init (&iter, out_settings); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) { - __NMTST_LOG (g_message, ">>> differences in setting '%s':", name); + __NMTST_LOG (g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails"); + if (out_settings) { + g_hash_table_iter_init (&iter, out_settings); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) { + __NMTST_LOG (g_message, ">>> differences in setting '%s':", name); - g_hash_table_iter_init (&iter2, out_settings); - while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL)) - __NMTST_LOG (g_message, ">>> differences in setting '%s.%s':", name, pname); + g_hash_table_iter_init (&iter2, setting); + while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL)) + __NMTST_LOG (g_message, ">>> differences in setting '%s.%s'", name, pname); + } } } g_assert (compare); @@ -1053,8 +1231,8 @@ typedef enum { g_variant_builder_add (&__setting_builder, "{sv}", \ __cur_property_name, \ __property_val); \ - } else \ - g_variant_unref (__property_val); \ + } \ + g_variant_unref (__property_val); \ } \ \ if (__cur_setting_name) \ diff --git a/include/nm-utils-internal.h b/include/nm-utils-internal.h index c002b6c1..227a210b 100644 --- a/include/nm-utils-internal.h +++ b/include/nm-utils-internal.h @@ -100,4 +100,77 @@ _found; \ }) +/*****************************************************************************/ + +#define NM_DEFINE_SINGLETON_INSTANCE(TYPE) \ +static TYPE *singleton_instance + +#define NM_DEFINE_SINGLETON_WEAK_REF(TYPE) \ +NM_DEFINE_SINGLETON_INSTANCE (TYPE); \ +static void \ +_singleton_instance_weak_ref_cb (gpointer data, \ + GObject *where_the_object_was) \ +{ \ + nm_log_dbg (LOGD_CORE, "disposing %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + singleton_instance = NULL; \ +} \ +static inline void \ +nm_singleton_instance_weak_ref_register (void) \ +{ \ + g_object_weak_ref (G_OBJECT (singleton_instance), _singleton_instance_weak_ref_cb, NULL); \ +} + +#define NM_DEFINE_SINGLETON_DESTRUCTOR(TYPE) \ +NM_DEFINE_SINGLETON_INSTANCE (TYPE); \ +static void __attribute__((destructor)) \ +_singleton_destructor (void) \ +{ \ + if (singleton_instance) { \ + if (G_OBJECT (singleton_instance)->ref_count > 1) \ + nm_log_dbg (LOGD_CORE, "disown %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + g_object_unref (singleton_instance); \ + } \ +} + +/* By default, the getter will assert that the singleton will be created only once. You can + * change this by redefining NM_DEFINE_SINGLETON_ALLOW_MULTIPLE. */ +#ifndef NM_DEFINE_SINGLETON_ALLOW_MULTIPLE +#define NM_DEFINE_SINGLETON_ALLOW_MULTIPLE FALSE +#endif + +#define NM_DEFINE_SINGLETON_GETTER(TYPE, GETTER, GTYPE, ...) \ +NM_DEFINE_SINGLETON_INSTANCE (TYPE); \ +NM_DEFINE_SINGLETON_WEAK_REF (TYPE); \ +TYPE * \ +GETTER (void) \ +{ \ + if (G_UNLIKELY (!singleton_instance)) { \ + static char _already_created = FALSE; \ +\ + g_assert (!_already_created || (NM_DEFINE_SINGLETON_ALLOW_MULTIPLE)); \ + _already_created = TRUE;\ + singleton_instance = (g_object_new (GTYPE, ##__VA_ARGS__, NULL)); \ + g_assert (singleton_instance); \ + nm_singleton_instance_weak_ref_register (); \ + nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + } \ + return singleton_instance; \ +} \ +NM_DEFINE_SINGLETON_DESTRUCTOR(TYPE) + +/*****************************************************************************/ + +static inline gboolean +nm_clear_g_source (guint *id) +{ + if (id && *id) { + g_source_remove (*id); + *id = 0; + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ + #endif |