diff options
Diffstat (limited to 'src/tests/refcount-tests.c')
-rw-r--r-- | src/tests/refcount-tests.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/tests/refcount-tests.c b/src/tests/refcount-tests.c new file mode 100644 index 0000000..fad2405 --- /dev/null +++ b/src/tests/refcount-tests.c @@ -0,0 +1,239 @@ +/* + SSSD + + Reference counting tests. + + Authors: + Martin Nagy <mnagy@redhat.com> + + Copyright (C) Red Hat, Inc 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <check.h> +#include <talloc.h> +#include <tevent.h> +#include <popt.h> + +#include "tests/common_check.h" +#include "util/util.h" + +/* Interface under test */ +#include "util/refcount.h" + +/* Fail the test if object 'obj' does not have 'num' references. */ +#define REF_ASSERT(obj, num) \ + ck_assert_msg(((obj)->DO_NOT_TOUCH_THIS_MEMBER_refcount == (num)), \ + "Reference count of " #obj " should be %d but is %d", \ + (num), (obj)->DO_NOT_TOUCH_THIS_MEMBER_refcount) + +#define FILLER_SIZE 32 + +struct foo { + REFCOUNT_COMMON; + char a[FILLER_SIZE]; + char b[FILLER_SIZE]; +}; + +struct bar { + char a[FILLER_SIZE]; + REFCOUNT_COMMON; + char b[FILLER_SIZE]; +}; + +struct baz { + char a[FILLER_SIZE]; + char b[FILLER_SIZE]; + REFCOUNT_COMMON; +}; + +#define SET_FILLER(target) do { \ + memset((target)->a, 'a', FILLER_SIZE); \ + memset((target)->b, 'b', FILLER_SIZE); \ +} while (0) + +#define CHECK_FILLER(target) do { \ + int _counter; \ + for (_counter = 0; _counter < FILLER_SIZE; _counter++) { \ + ck_assert_msg((target)->a[_counter] == 'a', "Corrupted memory in " \ + #target "->a[%d] of size %d", _counter, FILLER_SIZE); \ + ck_assert_msg((target)->b[_counter] == 'b', "Corrupted memory in " \ + #target "->b[%d] of size %d", _counter, FILLER_SIZE); \ + } \ +} while (0) + +struct container { + struct foo *foo; + struct bar *bar; + struct baz *baz; +}; + +static struct container *global; + +START_TEST(test_refcount_basic) +{ + struct container *containers; + int i; + + /* First allocate our global storage place. */ + global = talloc(NULL, struct container); + sss_ck_fail_if_msg(global == NULL, "Failed to allocate memory"); + + /* Allocate foo. */ + global->foo = rc_alloc(global, struct foo); + sss_ck_fail_if_msg(global->foo == NULL, "Failed to allocate memory"); + SET_FILLER(global->foo); + REF_ASSERT(global->foo, 1); + + /* Allocate bar. */ + global->bar = rc_alloc(global, struct bar); + sss_ck_fail_if_msg(global->bar == NULL, "Failed to allocate memory"); + SET_FILLER(global->bar); + REF_ASSERT(global->bar, 1); + + /* Allocate baz. */ + global->baz = rc_alloc(global, struct baz); + sss_ck_fail_if_msg(global->baz == NULL, "Failed to allocate memory"); + SET_FILLER(global->baz); + REF_ASSERT(global->baz, 1); + + /* Try multiple attaches. */ + containers = talloc_array(NULL, struct container, 100); + sss_ck_fail_if_msg(containers == NULL, "Failed to allocate memory"); + for (i = 0; i < 100; i++) { + containers[i].foo = rc_reference(containers, struct foo, global->foo); + containers[i].bar = rc_reference(containers, struct bar, global->bar); + containers[i].baz = rc_reference(containers, struct baz, global->baz); + REF_ASSERT(containers[i].foo, i + 2); + REF_ASSERT(global->foo, i + 2); + REF_ASSERT(containers[i].bar, i + 2); + REF_ASSERT(global->bar, i + 2); + REF_ASSERT(containers[i].baz, i + 2); + REF_ASSERT(global->baz, i + 2); + } + talloc_free(containers); + + CHECK_FILLER(global->foo); + CHECK_FILLER(global->bar); + CHECK_FILLER(global->baz); + + REF_ASSERT(global->foo, 1); + REF_ASSERT(global->bar, 1); + REF_ASSERT(global->baz, 1); + + talloc_free(global); +} +END_TEST + +START_TEST(test_refcount_swap) +{ + void *tmp_ctx; + struct container *container1; + struct container *container2; + + tmp_ctx = talloc_new(NULL); + + ck_leaks_push(tmp_ctx); + + container1 = talloc(tmp_ctx, struct container); + container2 = talloc(tmp_ctx, struct container); + + /* Allocate. */ + container1->foo = rc_alloc(container1, struct foo); + sss_ck_fail_if_msg(container1->foo == NULL, "Failed to allocate memory"); + SET_FILLER(container1->foo); + + /* Reference. */ + container2->foo = rc_reference(container2, struct foo, container1->foo); + sss_ck_fail_if_msg(container2->foo == NULL, "Failed to allocate memory"); + + /* Make sure everything is as it should be. */ + ck_assert_msg(container1->foo == container2->foo, + "Values have to be equal. %p == %p", + container1->foo, container2->foo); + REF_ASSERT(container1->foo, 2); + + /* Free in reverse order. */ + talloc_free(container1); + REF_ASSERT(container2->foo, 1); + CHECK_FILLER(container2->foo); + talloc_free(container2); + + ck_leaks_pop(tmp_ctx); + talloc_free(tmp_ctx); +} +END_TEST + +Suite *create_suite(void) +{ + Suite *s = suite_create("refcount"); + + TCase *tc = tcase_create("REFCOUNT Tests"); + + /* Do some testing */ + tcase_add_checked_fixture(tc, ck_leak_check_setup, ck_leak_check_teardown); + tcase_add_test(tc, test_refcount_basic); + tcase_add_test(tc, test_refcount_swap); + + /* Add all test cases to the test suite */ + suite_add_tcase(s, tc); + + return s; +} + +int main(int argc, const char *argv[]) +{ + int opt; + poptContext pc; + int failure_count; + Suite *suite; + SRunner *sr; + int debug = 0; + + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_DEBUG_OPTS + POPT_TABLEEND + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + poptFreeContext(pc); + + DEBUG_CLI_INIT(debug); + + tests_set_cwd(); + + suite = create_suite(); + sr = srunner_create(suite); + /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */ + srunner_run_all(sr, CK_ENV); + failure_count = srunner_ntests_failed(sr); + srunner_free(sr); + return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + |