diff --git a/glib/tests/meson.build b/glib/tests/meson.build index e0619c475..cf05bc74f 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -47,6 +47,8 @@ glib_tests = [ 'queue', 'rand', 'rec-mutex', + 'refcount', + 'refcount-macro', 'regex', 'rwlock', 'scannerapi', @@ -108,14 +110,23 @@ slow_tests = [ foreach test_name : glib_tests deps = [libm, thread_dep, libglib_dep] + source = test_name + '.c' + c_args = test_cargs + ['-DPCRE_STATIC'] if test_name == 'regex' deps += [pcre] endif if test_name == 'gdatetime' deps += [libintl] endif - exe = executable(test_name, '@0@.c'.format(test_name), - c_args : ['-DPCRE_STATIC'] + test_cargs, + # We build the refcount test twice: one to test the function-based API, + # and the other to test the macro-based API that is used when disabling + # checks + if test_name == 'refcount-macro' + source = 'refcount.c' + c_args += ['-DG_DISABLE_CHECKS'] + endif + exe = executable(test_name, source, + c_args : c_args, dependencies : deps, install : false, ) diff --git a/glib/tests/refcount.c b/glib/tests/refcount.c new file mode 100644 index 000000000..dfccc92c7 --- /dev/null +++ b/glib/tests/refcount.c @@ -0,0 +1,221 @@ +/* refcount.c: Tests for reference counting types + * + * Copyright 2018 Emmanuele Bassi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include + +/* test_grefcount: test the behavior of the grefcount API */ +static void +test_grefcount (void) +{ + grefcount a, b; + + /* init(a): 1 */ + g_ref_count_init (&a); + if (g_test_verbose ()) + g_test_message ("init(a) := %d\n", (int) a); + g_assert_true (g_ref_count_compare (&a, 1)); + + /* inc(a): 2 */ + g_ref_count_inc (&a); + if (g_test_verbose ()) + g_test_message ("inc(a) := %d\n", (int) a); + g_assert_false (g_ref_count_compare (&a, 1)); + g_assert_false (g_ref_count_compare (&a, G_MAXINT)); + + /* b = a = 2 */ + b = a; + if (g_test_verbose ()) + g_test_message ("a := %d, b := %d\n", (int) a, (int) b); + + /* inc(a): 3 */ + g_ref_count_inc (&a); + if (g_test_verbose ()) + g_test_message ("inc(a) := %d\n", (int) a); + + /* dec(b) = 1 */ + if (g_test_verbose ()) + g_test_message ("dec(b) := %d + 1\n", (int) b); + g_assert_false (g_ref_count_dec (&b)); + + /* dec(a) = 2 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_false (g_ref_count_dec (&a)); + + /* dec(b) = 0 */ + if (g_test_verbose ()) + g_test_message ("dec(b) := %d + 1\n", (int) b); + g_assert_true (g_ref_count_dec (&b)); + + /* dec(a) = 1 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_false (g_ref_count_dec (&a)); + + /* dec(a) = 0 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_true (g_ref_count_dec (&a)); +} + +/* test_grefcount_saturation: Saturating a grefcount counter + * does not cause an overflow; additionally, if we're building + * with checks enabled, it'll cause a warning + */ +static void +test_grefcount_saturation (void) +{ + if (g_test_subprocess ()) + { + grefcount a; + + /* We're breaking abstraction here for convenience */ + a = G_MININT + 1; + + g_ref_count_inc (&a); + g_assert_true (a == G_MININT); + + g_ref_count_inc (&a); + g_assert_true (a == G_MININT); + + exit (0); + } + + g_test_trap_subprocess (NULL, 0, 0); + +#ifndef G_DISABLE_CHECKS + /* Ensure that we got a warning when building with checks; the + * test will fail because of the critical warning being caught + * by GTest + */ + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*saturation*"); +#else + /* With checks disabled we don't get any warning */ + g_test_trap_assert_passed (); +#endif +} + +/* test_gatomicrefcount: test the behavior of the gatomicrefcount API */ +static void +test_gatomicrefcount (void) +{ + gatomicrefcount a, b; + + /* init(a): 1 */ + g_atomic_ref_count_init (&a); + if (g_test_verbose ()) + g_test_message ("init(a) := %d\n", (int) a); + g_assert_true (g_atomic_ref_count_compare (&a, 1)); + + /* inc(a): 2 */ + g_atomic_ref_count_inc (&a); + if (g_test_verbose ()) + g_test_message ("inc(a) := %d\n", (int) a); + g_assert_false (g_atomic_ref_count_compare (&a, 1)); + g_assert_false (g_atomic_ref_count_compare (&a, G_MAXINT)); + + /* b = a = 2 */ + b = a; + if (g_test_verbose ()) + g_test_message ("a := %d, b := %d\n", (int) a, (int) b); + + /* inc(a): 3 */ + g_atomic_ref_count_inc (&a); + if (g_test_verbose ()) + g_test_message ("inc(a) := %d\n", (int) a); + + /* dec(b) = 1 */ + if (g_test_verbose ()) + g_test_message ("dec(b) := %d + 1\n", (int) b); + g_assert_false (g_atomic_ref_count_dec (&b)); + + /* dec(a) = 2 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_false (g_atomic_ref_count_dec (&a)); + + /* dec(b) = 0 */ + if (g_test_verbose ()) + g_test_message ("dec(b) := %d + 1\n", (int) b); + g_assert_true (g_atomic_ref_count_dec (&b)); + + /* dec(a) = 1 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_false (g_atomic_ref_count_dec (&a)); + + /* dec(a) = 0 */ + if (g_test_verbose ()) + g_test_message ("dec(a) := %d + 1\n", (int) a); + g_assert_true (g_atomic_ref_count_dec (&a)); +} + +/* test_grefcount_saturation: Saturating a gatomicrefcount counter + * does not cause an overflow; additionally, if we're building + * with checks enabled, it'll cause a warning + */ +static void +test_gatomicrefcount_saturation (void) +{ + if (g_test_subprocess ()) + { + gatomicrefcount a; + + /* We're breaking abstraction here for convenience */ + a = G_MAXINT - 1; + + g_atomic_ref_count_inc (&a); + g_assert_true (a == G_MAXINT); + + g_atomic_ref_count_inc (&a); + g_assert_true (a == G_MAXINT); + + exit (0); + } + + g_test_trap_subprocess (NULL, 0, 0); + +#ifndef G_DISABLE_CHECKS + /* Ensure that we got a warning when building with checks; the + * test will fail because of the critical warning being caught + * by GTest + */ + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*saturation*"); +#else + /* With checks disabled we don't get any warning */ + g_test_trap_assert_passed (); +#endif +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/refcount/grefcount", test_grefcount); + g_test_add_func ("/refcount/grefcount/saturation", test_grefcount_saturation); + + g_test_add_func ("/refcount/gatomicrefcount", test_gatomicrefcount); + g_test_add_func ("/refcount/gatomicrefcount/saturation", test_gatomicrefcount_saturation); + + return g_test_run (); +}