From 156dcbc12e487c1a3649f8e1b9b474d569c67969 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 10:21:32 +0100 Subject: [PATCH 01/48] Add test runner for unit tests in libstrongswan --- configure.in | 1 + src/libstrongswan/Makefile.am | 7 +++++ src/libstrongswan/tests/.gitignore | 1 + src/libstrongswan/tests/Makefile.am | 15 +++++++++++ src/libstrongswan/tests/test_runner.c | 39 +++++++++++++++++++++++++++ src/libstrongswan/tests/test_runner.h | 21 +++++++++++++++ 6 files changed, 84 insertions(+) create mode 100644 src/libstrongswan/tests/.gitignore create mode 100644 src/libstrongswan/tests/Makefile.am create mode 100644 src/libstrongswan/tests/test_runner.c create mode 100644 src/libstrongswan/tests/test_runner.h diff --git a/configure.in b/configure.in index 8df0c2a0b..b366a6a0d 100644 --- a/configure.in +++ b/configure.in @@ -1320,6 +1320,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/gcm/Makefile src/libstrongswan/plugins/af_alg/Makefile src/libstrongswan/plugins/test_vectors/Makefile + src/libstrongswan/tests/Makefile src/libhydra/Makefile src/libhydra/plugins/attr/Makefile src/libhydra/plugins/attr_sql/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 2465fb09d..bde69645f 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -455,3 +455,10 @@ if MONOLITHIC libstrongswan_la_LIBADD += plugins/test_vectors/libstrongswan-test-vectors.la endif endif + +if UNITTESTS +if MONOLITHIC + SUBDIRS += . +endif + SUBDIRS += tests +endif diff --git a/src/libstrongswan/tests/.gitignore b/src/libstrongswan/tests/.gitignore new file mode 100644 index 000000000..35429f617 --- /dev/null +++ b/src/libstrongswan/tests/.gitignore @@ -0,0 +1 @@ +test_runner diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am new file mode 100644 index 000000000..215cdde8b --- /dev/null +++ b/src/libstrongswan/tests/Makefile.am @@ -0,0 +1,15 @@ +TESTS = test_runner + +check_PROGRAMS = $(TESTS) + +test_runner_SOURCES = \ + test_runner.c test_runner.h + + +test_runner_CFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + @CHECK_CFLAGS@ + +test_runner_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + @CHECK_LIBS@ diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c new file mode 100644 index 000000000..264dd700d --- /dev/null +++ b/src/libstrongswan/tests/test_runner.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include "test_runner.h" + +#include + +int main() +{ + SRunner *sr; + int nf; + + /* if a test fails there is no cleanup, so disable leak detective */ + setenv("LEAK_DETECTIVE_DISABLE", "1", 1); + + library_init(NULL); + + sr = srunner_create(NULL); + + srunner_run_all(sr, CK_NORMAL); + nf = srunner_ntests_failed(sr); + + srunner_free(sr); + library_deinit(); + + return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h new file mode 100644 index 000000000..f7a7d7510 --- /dev/null +++ b/src/libstrongswan/tests/test_runner.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#ifndef TEST_RUNNER_H_ +#define TEST_RUNNER_H_ + +#include + +#endif /** TEST_RUNNER_H_ */ From f15fcdc9d87a91a45ec1ca8ab9d4626b0b811514 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 10:41:54 +0100 Subject: [PATCH 02/48] Add tests for enumerator_t --- src/libstrongswan/tests/Makefile.am | 3 +- src/libstrongswan/tests/test_enumerator.c | 191 ++++++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 2 + 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_enumerator.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 215cdde8b..b16180b8d 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -3,7 +3,8 @@ TESTS = test_runner check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ - test_runner.c test_runner.h + test_runner.c test_runner.h \ + test_enumerator.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_enumerator.c b/src/libstrongswan/tests/test_enumerator.c new file mode 100644 index 000000000..882e8cc61 --- /dev/null +++ b/src/libstrongswan/tests/test_enumerator.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include +#include + +/******************************************************************************* + * token test + */ + +static const char *token_results1[] = { "abc", "cde", "efg" }; +static const char *token_results2[] = { "a", "b", "c" }; + +static struct { + char *string; + char *sep; + char *trim; + const char **results; +} token_tests[] = { + {"abc, cde, efg", ",", " ", token_results1}, + {" abc 1:2 cde;3 4efg5. ", ":;.,", " 12345", token_results1}, + {"abc.cde,efg", ",.", "", token_results1}, + {" abc cde efg ", " ", " ", token_results1}, + {"a'abc' c 'cde' cefg", " ", " abcd", token_results1}, + {"'abc' abc 'cde'd 'efg'", " ", " abcd", token_results1}, + + {"a, b, c", ",", " ", token_results2}, + {"a,b,c", ",", " ", token_results2}, + {" a 1:2 b;3 4c5. ", ":;.,", " 12345", token_results2}, + {"a.b,c", ",.", "", token_results2}, + {" a b c ", " ", " ", token_results2}, +}; + +START_TEST(test_token) +{ + enumerator_t *enumerator; + const char **results; + char *token; + int tok = 0; + + enumerator = enumerator_create_token(token_tests[_i].string, + token_tests[_i].sep, token_tests[_i].trim); + results = token_tests[_i].results; + while (enumerator->enumerate(enumerator, &token)) + { + switch (tok) + { + case 0: + case 1: + case 2: + ck_assert_str_eq(token, results[tok]); + break; + default: + fail("unexpected token '%s'", token); + } + tok++; + } + fail_if(tok != 3, "not enough tokens (%d) extracted from '%s'", + tok, token_tests[_i].string); + enumerator->destroy(enumerator); +} +END_TEST + +/******************************************************************************* + * utility for filtered and nested tests + */ + +static void destroy_data(void *data) +{ + fail_if(data != (void*)101, "data does not match '101' in destructor"); +} + +/******************************************************************************* + * filtered test + */ + +static bool filter(void *data, int *v, int *vo, int *w, int *wo, + int *x, int *xo, int *y, int *yo, int *z, int *zo) +{ + int val = *v; + + *vo = val++; + *wo = val++; + *xo = val++; + *yo = val++; + *zo = val++; + fail_if(data != (void*)101, "data does not match '101' in filter function"); + return TRUE; +} + +START_TEST(test_filtered) +{ + int round, v, w, x, y, z; + linked_list_t *list; + enumerator_t *enumerator; + + list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4, + (void*)5, NULL); + + round = 1; + enumerator = enumerator_create_filter(list->create_enumerator(list), + (void*)filter, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z)) + { + ck_assert_int_eq(v, round); + ck_assert_int_eq(w, round + 1); + ck_assert_int_eq(x, round + 2); + ck_assert_int_eq(y, round + 3); + ck_assert_int_eq(z, round + 4); + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); +} +END_TEST + +/******************************************************************************* + * nested test + */ + +static enumerator_t* create_inner(linked_list_t *outer, void *data) +{ + fail_if(data != (void*)101, "data does not match '101' in nested constr."); + return outer->create_enumerator(outer); +} + +START_TEST(test_nested) +{ + int round, x; + linked_list_t *list, *l1, *l2, *l3; + enumerator_t *enumerator; + + l1 = linked_list_create_with_items((void*)1, (void*)2, NULL); + l2 = linked_list_create(); + l3 = linked_list_create_with_items((void*)3, (void*)4, (void*)5, NULL); + list = linked_list_create_with_items(l1, l2, l3, NULL); + + round = 1; + enumerator = enumerator_create_nested(list->create_enumerator(list), + (void*)create_inner, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + l1->destroy(l1); + l2->destroy(l2); + l3->destroy(l3); +} +END_TEST + +Suite *enumerator_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("enumerator"); + + tc = tcase_create("tokens"); + tcase_add_loop_test(tc, test_token, 0, countof(token_tests)); + suite_add_tcase(s, tc); + + tc = tcase_create("filtered"); + tcase_add_test(tc, test_filtered); + suite_add_tcase(s, tc); + + tc = tcase_create("nested"); + tcase_add_test(tc, test_nested); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 264dd700d..2c327c2ee 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -28,6 +28,7 @@ int main() library_init(NULL); sr = srunner_create(NULL); + srunner_add_suite(sr, enumerator_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index f7a7d7510..1bf9a5f29 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -18,4 +18,6 @@ #include +Suite *enumerator_suite_create(); + #endif /** TEST_RUNNER_H_ */ From 0d67c8329b19987613d00f1d06782b1c6630607b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 10:49:08 +0100 Subject: [PATCH 03/48] Redirect test runner output to stderr This allows redirecting stdout of 'make check' to /dev/null. --- src/libstrongswan/tests/test_runner.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 2c327c2ee..e0973573f 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -13,6 +13,8 @@ * for more details. */ +#include + #include "test_runner.h" #include @@ -24,6 +26,8 @@ int main() /* if a test fails there is no cleanup, so disable leak detective */ setenv("LEAK_DETECTIVE_DISABLE", "1", 1); + /* redirect all output to stderr (to redirect make's stdout to /dev/null) */ + dup2(2, 1); library_init(NULL); From ff8f12298f82b86dcdb090908f7e476d85f1dea9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 12:18:44 +0100 Subject: [PATCH 04/48] Add basic tests for linked_list_t --- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_linked_list.c | 285 +++++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 4 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_linked_list.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index b16180b8d..bf0f02a5b 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -4,7 +4,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ - test_enumerator.c + test_linked_list.c test_enumerator.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_linked_list.c b/src/libstrongswan/tests/test_linked_list.c new file mode 100644 index 000000000..d2f6147e2 --- /dev/null +++ b/src/libstrongswan/tests/test_linked_list.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include + +/******************************************************************************* + * test fixture + */ + +static linked_list_t *list; + +static void setup_list() +{ + void *x = NULL; + + list = linked_list_create(); + ck_assert_int_eq(list->get_count(list), 0); + ck_assert(list->get_first(list, &x) == NOT_FOUND); + ck_assert(list->get_last(list, &x) == NOT_FOUND); +} + +static void teardown_list() +{ + list->destroy(list); +} + +/******************************************************************************* + * insert first/last + */ + +START_TEST(test_insert_first) +{ + void *a = (void*)1, *b = (void*)2, *x = NULL; + + list->insert_first(list, a); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(list->get_first(list, &x) == SUCCESS); + ck_assert(x == a); + ck_assert(list->get_last(list, &x) == SUCCESS); + ck_assert(x == a); + + list->insert_first(list, b); + ck_assert_int_eq(list->get_count(list), 2); + ck_assert(list->get_first(list, &x) == SUCCESS); + ck_assert(x == b); + ck_assert(list->get_last(list, &x) == SUCCESS); + ck_assert(x == a); +} +END_TEST + +START_TEST(test_insert_last) +{ + void *a = (void*)1, *b = (void*)2, *x = NULL; + + list->insert_last(list, a); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(list->get_first(list, &x) == SUCCESS); + ck_assert(x == a); + ck_assert(list->get_last(list, &x) == SUCCESS); + ck_assert(x == a); + + list->insert_last(list, b); + ck_assert_int_eq(list->get_count(list), 2); + ck_assert(list->get_first(list, &x) == SUCCESS); + ck_assert(x == a); + ck_assert(list->get_last(list, &x) == SUCCESS); + ck_assert(x == b); +} +END_TEST + +/******************************************************************************* + * remove first/last + */ + +START_TEST(test_remove_first) +{ + void *a = (void*)1, *b = (void*)2, *x = NULL; + + list->insert_first(list, a); + list->insert_first(list, b); + ck_assert(list->remove_first(list, &x) == SUCCESS); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(x == b); + ck_assert(list->remove_first(list, &x) == SUCCESS); + ck_assert_int_eq(list->get_count(list), 0); + ck_assert(x == a); + ck_assert(list->remove_first(list, &x) == NOT_FOUND); + ck_assert(list->remove_last(list, &x) == NOT_FOUND); +} +END_TEST + +START_TEST(test_remove_last) +{ + void *a = (void*)1, *b = (void*)2, *x = NULL; + + list->insert_first(list, a); + list->insert_first(list, b); + ck_assert(list->remove_last(list, &x) == SUCCESS); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(x == a); + ck_assert(list->remove_last(list, &x) == SUCCESS); + ck_assert_int_eq(list->get_count(list), 0); + ck_assert(x == b); + ck_assert(list->remove_first(list, &x) == NOT_FOUND); + ck_assert(list->remove_last(list, &x) == NOT_FOUND); +} +END_TEST + +/******************************************************************************* + * helper function for remove and find tests + */ + +static bool match_a(void *item, void *a) +{ + ck_assert(a == (void*)1); + return item == a; +} + +static bool match_b(void *item, void *b) +{ + ck_assert(b == (void*)2); + return item == b; +} + +/******************************************************************************* + * remove + */ + +START_TEST(test_remove) +{ + void *a = (void*)1, *b = (void*)2; + + list->insert_first(list, a); + ck_assert(list->remove(list, a, NULL) == 1); + ck_assert_int_eq(list->get_count(list), 0); + + list->insert_last(list, a); + list->insert_last(list, a); + list->insert_last(list, a); + list->insert_last(list, b); + ck_assert(list->remove(list, a, NULL) == 3); + ck_assert(list->remove(list, a, NULL) == 0); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(list->remove(list, b, NULL) == 1); + ck_assert(list->remove(list, b, NULL) == 0); +} +END_TEST + +START_TEST(test_remove_callback) +{ + void *a = (void*)1, *b = (void*)2; + + list->insert_last(list, a); + list->insert_last(list, b); + list->insert_last(list, a); + list->insert_last(list, b); + ck_assert(list->remove(list, a, match_a) == 2); + ck_assert(list->remove(list, a, match_a) == 0); + ck_assert_int_eq(list->get_count(list), 2); + ck_assert(list->remove(list, b, match_b) == 2); + ck_assert(list->remove(list, b, match_b) == 0); + ck_assert_int_eq(list->get_count(list), 0); +} +END_TEST + +/******************************************************************************* + * find + */ + +static bool match_a_b(void *item, void *a, void *b) +{ + ck_assert(a == (void*)1); + ck_assert(b == (void*)2); + return item == a || item == b; +} + +START_TEST(test_find) +{ + void *a = (void*)1, *b = (void*)2; + + ck_assert(list->find_first(list, NULL, &a) == NOT_FOUND); + ck_assert(list->find_last(list, NULL, &a) == NOT_FOUND); + list->insert_last(list, a); + ck_assert(list->find_first(list, NULL, &a) == SUCCESS); + ck_assert(list->find_first(list, NULL, &b) == NOT_FOUND); + ck_assert(list->find_last(list, NULL, &a) == SUCCESS); + ck_assert(list->find_last(list, NULL, &b) == NOT_FOUND); + list->insert_last(list, b); + ck_assert(list->find_first(list, NULL, &a) == SUCCESS); + ck_assert(list->find_first(list, NULL, &b) == SUCCESS); + ck_assert(list->find_last(list, NULL, &a) == SUCCESS); + ck_assert(list->find_last(list, NULL, &b) == SUCCESS); + + ck_assert(list->find_first(list, NULL, NULL) == NOT_FOUND); + ck_assert(list->find_last(list, NULL, NULL) == NOT_FOUND); +} +END_TEST + +START_TEST(test_find_callback) +{ + void *a = (void*)1, *b = (void*)2, *x = NULL; + + ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == NOT_FOUND); + list->insert_last(list, a); + ck_assert(list->find_first(list, (linked_list_match_t)match_a, NULL, a) == SUCCESS); + x = NULL; + ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS); + ck_assert(a == x); + ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == NOT_FOUND); + ck_assert(a == x); + x = NULL; + ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS); + ck_assert(a == x); + + ck_assert(list->find_last(list, (linked_list_match_t)match_a, NULL, a) == SUCCESS); + x = NULL; + ck_assert(list->find_last(list, (linked_list_match_t)match_a, &x, a) == SUCCESS); + ck_assert(a == x); + ck_assert(list->find_last(list, (linked_list_match_t)match_b, &x, b) == NOT_FOUND); + ck_assert(a == x); + x = NULL; + ck_assert(list->find_last(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS); + ck_assert(a == x); + + list->insert_last(list, b); + ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS); + ck_assert(a == x); + ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == SUCCESS); + ck_assert(b == x); + ck_assert(list->find_last(list, (linked_list_match_t)match_a, &x, a) == SUCCESS); + ck_assert(a == x); + ck_assert(list->find_last(list, (linked_list_match_t)match_b, &x, b) == SUCCESS); + ck_assert(b == x); + x = NULL; + ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS); + ck_assert(a == x); + x = NULL; + ck_assert(list->find_last(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS); + ck_assert(b == x); +} +END_TEST + +Suite *linked_list_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("linked list"); + + tc = tcase_create("insert/get"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_insert_first); + tcase_add_test(tc, test_insert_last); + suite_add_tcase(s, tc); + + tc = tcase_create("remove"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_remove_first); + tcase_add_test(tc, test_remove_last); + tcase_add_test(tc, test_remove); + tcase_add_test(tc, test_remove_callback); + suite_add_tcase(s, tc); + + tc = tcase_create("find"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_find); + tcase_add_test(tc, test_find_callback); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index e0973573f..9baad463e 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -33,6 +33,7 @@ int main() sr = srunner_create(NULL); srunner_add_suite(sr, enumerator_suite_create()); + srunner_add_suite(sr, linked_list_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 1bf9a5f29..9c0aba4bf 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -19,5 +19,6 @@ #include Suite *enumerator_suite_create(); +Suite *linked_list_suite_create(); #endif /** TEST_RUNNER_H_ */ From d3b06618f8be6c7468799b737ccf40a447e104f0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 12:36:51 +0100 Subject: [PATCH 05/48] Some minor Doxygen fixes for linked_list_t --- src/libstrongswan/collections/linked_list.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/collections/linked_list.h b/src/libstrongswan/collections/linked_list.h index da539a231..81eca8945 100644 --- a/src/libstrongswan/collections/linked_list.h +++ b/src/libstrongswan/collections/linked_list.h @@ -82,6 +82,7 @@ struct linked_list_t { * current position. * * @param enumerator enumerator to check + * @return TRUE if more elements follow after the current item */ bool (*has_more)(linked_list_t *this, enumerator_t *enumerator); @@ -180,7 +181,8 @@ struct linked_list_t { */ status_t (*get_last) (linked_list_t *this, void **item); - /** Find the first matching element in the list. + /** + * Find the first matching element in the list. * * The first object passed to the match function is the current list item, * followed by the user supplied data. @@ -200,7 +202,8 @@ struct linked_list_t { status_t (*find_first) (linked_list_t *this, linked_list_match_t match, void **item, ...); - /** Find the last matching element in the list. + /** + * Find the last matching element in the list. * * The first object passed to the match function is the current list item, * followed by the user supplied data. From 26e8375b14cd635559de9b0df8ba903dc1266207 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 13:07:23 +0100 Subject: [PATCH 06/48] Add tests combining linked_list_t and enumerators --- src/libstrongswan/tests/Makefile.am | 2 +- .../tests/test_linked_list_enumerator.c | 305 ++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 4 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_linked_list_enumerator.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index bf0f02a5b..0fd404014 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -4,7 +4,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ - test_linked_list.c test_enumerator.c + test_linked_list.c test_enumerator.c test_linked_list_enumerator.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c new file mode 100644 index 000000000..ed098c07c --- /dev/null +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include + +/******************************************************************************* + * test fixture + */ + +static linked_list_t *list; + +static void setup_list() +{ + list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4, + (void*)5, NULL); + ck_assert_int_eq(list->get_count(list), 5); +} + +static void teardown_list() +{ + list->destroy(list); +} + +/******************************************************************************* + * enumeration + */ + +START_TEST(test_enumerate) +{ + enumerator_t *enumerator; + int round, x; + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + ck_assert_int_eq(round, 6); + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_reset_enumerator) +{ + enumerator_t *enumerator; + int round, x; + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + } + list->reset_enumerator(list, enumerator); + round = 1; + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + ck_assert_int_eq(round, 6); + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_has_more) +{ + enumerator_t *enumerator; + int round, x; + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + if (x == 2) + { + break; + } + } + ck_assert(list->has_more(list, enumerator)); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + ck_assert(!list->has_more(list, enumerator)); + ck_assert_int_eq(round, 6); + enumerator->destroy(enumerator); +} +END_TEST + +/******************************************************************************* + * insert before + */ + +START_TEST(test_insert_before) +{ + enumerator_t *enumerator; + int round, x; + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + if (x == 2) + { + list->insert_before(list, enumerator, (void*)6); + } + } + ck_assert_int_eq(list->get_count(list), 6); + list->reset_enumerator(list, enumerator); + round = 1; + while (enumerator->enumerate(enumerator, &x)) + { + if (round == 2 && x != 2) + { + ck_assert_int_eq(6, x); + } + else + { + ck_assert_int_eq(round, x); + round++; + } + } + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_insert_before_ends) +{ + enumerator_t *enumerator; + int round, x; + + enumerator = list->create_enumerator(list); + list->insert_before(list, enumerator, (void*)0); + ck_assert_int_eq(list->get_count(list), 6); + ck_assert(list->get_first(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 0); + round = 0; + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + list->insert_before(list, enumerator, (void*)6); + ck_assert_int_eq(list->get_count(list), 7); + ck_assert(list->get_last(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 6); + ck_assert(!list->has_more(list, enumerator)); + ck_assert(!enumerator->enumerate(enumerator, &x)); + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_insert_before_empty) +{ + enumerator_t *enumerator; + int x; + + list->destroy(list); + list = linked_list_create(); + enumerator = list->create_enumerator(list); + list->insert_before(list, enumerator, (void*)1); + ck_assert_int_eq(list->get_count(list), 1); + ck_assert(list->get_first(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 1); + ck_assert(list->get_last(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 1); + ck_assert(list->has_more(list, enumerator)); + ck_assert(enumerator->enumerate(enumerator, &x)); + ck_assert_int_eq(x, 1); + ck_assert(!list->has_more(list, enumerator)); + enumerator->destroy(enumerator); +} +END_TEST + +/******************************************************************************* + * replace / remove_at + */ + +START_TEST(test_replace) +{ + enumerator_t *enumerator; + int round, x; + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + list->replace(list, enumerator, (void*)(uintptr_t)(6 - round)); + round++; + } + list->reset_enumerator(list, enumerator); + round = 5; + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round--; + } + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_remove_at) +{ + enumerator_t *enumerator; + int round, x; + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + if (round == 2) + { + list->remove_at(list, enumerator); + } + round++; + } + ck_assert_int_eq(list->get_count(list), 4); + list->reset_enumerator(list, enumerator); + round = 1; + while (enumerator->enumerate(enumerator, &x)) + { + if (round == 2) + { /* skip removed item */ + round++; + } + ck_assert_int_eq(round, x); + round++; + } + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_remove_at_ends) +{ + enumerator_t *enumerator; + int x; + + enumerator = list->create_enumerator(list); + list->remove_at(list, enumerator); + ck_assert_int_eq(list->get_count(list), 5); + ck_assert(list->get_first(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 1); + while (enumerator->enumerate(enumerator, &x)) + { + } + list->remove_at(list, enumerator); + ck_assert_int_eq(list->get_count(list), 5); + ck_assert(list->get_last(list, (void*)&x) == SUCCESS); + ck_assert_int_eq(x, 5); + enumerator->destroy(enumerator); +} +END_TEST + +Suite *linked_list_enumerator_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("linked list and enumerators"); + + tc = tcase_create("enumerate"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_enumerate); + tcase_add_test(tc, test_reset_enumerator); + tcase_add_test(tc, test_has_more); + suite_add_tcase(s, tc); + + tc = tcase_create("insert_before()"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_insert_before); + tcase_add_test(tc, test_insert_before_ends); + tcase_add_test(tc, test_insert_before_empty); + suite_add_tcase(s, tc); + + tc = tcase_create("modify"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_replace); + tcase_add_test(tc, test_remove_at); + tcase_add_test(tc, test_remove_at_ends); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 9baad463e..dab532e3b 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -34,6 +34,7 @@ int main() sr = srunner_create(NULL); srunner_add_suite(sr, enumerator_suite_create()); srunner_add_suite(sr, linked_list_suite_create()); + srunner_add_suite(sr, linked_list_enumerator_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 9c0aba4bf..e297c88bc 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -20,5 +20,6 @@ Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); +Suite *linked_list_enumerator_suite_create(); #endif /** TEST_RUNNER_H_ */ From 3cbacad40b88ffc53e164ef0ad615dce61cab82e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 13:13:33 +0100 Subject: [PATCH 07/48] Remove obsolete enumerator/linked_list tests in unit_tester plugin --- src/libcharon/plugins/unit_tester/Makefile.am | 1 - src/libcharon/plugins/unit_tester/tests.h | 5 - .../unit_tester/tests/test_enumerator.c | 306 ------------------ 3 files changed, 312 deletions(-) delete mode 100644 src/libcharon/plugins/unit_tester/tests/test_enumerator.c diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index c46d2b85d..ec98dc689 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -12,7 +12,6 @@ endif libstrongswan_unit_tester_la_SOURCES = \ unit_tester.c unit_tester.h tests.h \ - tests/test_enumerator.c \ tests/test_auth_info.c \ tests/test_curl.c \ tests/test_mysql.c \ diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h index cd38c8a99..bc7e174f3 100644 --- a/src/libcharon/plugins/unit_tester/tests.h +++ b/src/libcharon/plugins/unit_tester/tests.h @@ -18,12 +18,7 @@ * @{ @ingroup unit_tester */ -DEFINE_TEST("linked_list_t->remove()", test_list_remove, FALSE) DEFINE_TEST("hashtable_t->remove_at()", test_hashtable_remove_at, FALSE) -DEFINE_TEST("simple enumerator", test_enumerate, FALSE) -DEFINE_TEST("nested enumerator", test_enumerate_nested, FALSE) -DEFINE_TEST("filtered enumerator", test_enumerate_filtered, FALSE) -DEFINE_TEST("token enumerator", test_enumerate_token, FALSE) DEFINE_TEST("auth cfg", test_auth_cfg, FALSE) DEFINE_TEST("CURL get", test_curl_get, FALSE) DEFINE_TEST("MySQL operations", test_mysql, FALSE) diff --git a/src/libcharon/plugins/unit_tester/tests/test_enumerator.c b/src/libcharon/plugins/unit_tester/tests/test_enumerator.c deleted file mode 100644 index 83b78c092..000000000 --- a/src/libcharon/plugins/unit_tester/tests/test_enumerator.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * 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 2 of the License, or (at your - * option) any later version. See . - * - * 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. - */ - -#include - - -/******************************************************************************* - * linked list remove test - ******************************************************************************/ -bool test_list_remove() -{ - void *a = (void*)1, *b = (void*)2; - linked_list_t *list; - - list = linked_list_create(); - list->insert_last(list, a); - if (list->remove(list, a, NULL) != 1) - { - return FALSE; - } - list->insert_last(list, a); - list->insert_first(list, a); - list->insert_last(list, a); - list->insert_last(list, b); - if (list->remove(list, a, NULL) != 3) - { - return FALSE; - } - if (list->remove(list, a, NULL) != 0) - { - return FALSE; - } - if (list->get_count(list) != 1) - { - return FALSE; - } - if (list->remove(list, b, NULL) != 1) - { - return FALSE; - } - if (list->remove(list, b, NULL) != 0) - { - return FALSE; - } - list->destroy(list); - return TRUE; -} - -/******************************************************************************* - * Simple insert first/last and enumerate test - ******************************************************************************/ -bool test_enumerate() -{ - int round, x; - void *a = (void*)4, *b = (void*)3, *c = (void*)2, *d = (void*)5, *e = (void*)1; - linked_list_t *list; - enumerator_t *enumerator; - - list = linked_list_create(); - - list->insert_last(list, a); - list->insert_first(list, b); - list->insert_first(list, c); - list->insert_last(list, d); - list->insert_first(list, e); - - round = 1; - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &x)) - { - if (round != x) - { - return FALSE; - } - round++; - } - enumerator->destroy(enumerator); - - list->destroy(list); - return TRUE; -} - -/******************************************************************************* - * nested enumerator test - ******************************************************************************/ - -static bool bad_data; - -static enumerator_t* create_inner(linked_list_t *outer, void *data) -{ - if (data != (void*)101) - { - bad_data = TRUE; - } - return outer->create_enumerator(outer); -} - - -static void destroy_data(void *data) -{ - if (data != (void*)101) - { - bad_data = TRUE; - } -} - -bool test_enumerate_nested() -{ - int round, x; - void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; - linked_list_t *list, *l1, *l2, *l3; - enumerator_t *enumerator; - - bad_data = FALSE; - list = linked_list_create(); - l1 = linked_list_create(); - l2 = linked_list_create(); - l3 = linked_list_create(); - list->insert_last(list, l1); - list->insert_last(list, l2); - list->insert_last(list, l3); - - l1->insert_last(l1, a); - l1->insert_last(l1, b); - l3->insert_last(l3, c); - l3->insert_last(l3, d); - l3->insert_last(l3, e); - - round = 1; - enumerator = enumerator_create_nested(list->create_enumerator(list), - (void*)create_inner, (void*)101, destroy_data); - while (enumerator->enumerate(enumerator, &x)) - { - if (round != x) - { - return FALSE; - } - round++; - } - enumerator->destroy(enumerator); - - list->destroy(list); - l1->destroy(l1); - l2->destroy(l2); - l3->destroy(l3); - return !bad_data; -} - - -/******************************************************************************* - * filtered enumerator test - ******************************************************************************/ -static bool filter(void *data, int *v, int *vo, int *w, int *wo, - int *x, int *xo, int *y, int *yo, int *z, int *zo) -{ - int val = *v; - - *vo = val++; - *wo = val++; - *xo = val++; - *yo = val++; - *zo = val++; - if (data != (void*)101) - { - return FALSE; - } - return TRUE; -} - -bool test_enumerate_filtered() -{ - int round, v, w, x, y, z; - void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; - linked_list_t *list; - enumerator_t *enumerator; - - bad_data = FALSE; - list = linked_list_create(); - - list->insert_last(list, a); - list->insert_last(list, b); - list->insert_last(list, c); - list->insert_last(list, d); - list->insert_last(list, e); - - round = 1; - enumerator = enumerator_create_filter(list->create_enumerator(list), - (void*)filter, (void*)101, destroy_data); - while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z)) - { - if (v != round || w != round + 1 || x != round + 2 || - y != round + 3 || z != round + 4) - { - return FALSE; - } - round++; - } - enumerator->destroy(enumerator); - - list->destroy(list); - return !bad_data; -} - -/******************************************************************************* - * token parser test - ******************************************************************************/ - -bool test_enumerate_token() -{ - enumerator_t *enumerator; - char *token; - int i, num; - struct { - char *string; - char *sep; - char *trim; - } tests1[] = { - {"abc, cde, efg", ",", " "}, - {" abc 1:2 cde;3 4efg5. ", ":;.,", " 12345"}, - {"abc.cde,efg", ",.", ""}, - {" abc cde efg ", " ", " "}, - {"a'abc' c 'cde' cefg", " ", " abcd"}, - {"'abc' abc 'cde'd 'efg'", " ", " abcd"}, - }, tests2[] = { - {"a, b, c", ",", " "}, - {"a,b,c", ",", " "}, - {" a 1:2 b;3 4c5. ", ":;.,", " 12345"}, - {"a.b,c", ",.", ""}, - {" a b c ", " ", " "}, - }; - - for (num = 0; num < countof(tests1); num++) - { - i = 0; - enumerator = enumerator_create_token(tests1[num].string, - tests1[num].sep, tests1[num].trim); - while (enumerator->enumerate(enumerator, &token)) - { - switch (i) - { - case 0: - if (!streq(token, "abc")) return FALSE; - break; - case 1: - if (!streq(token, "cde")) return FALSE; - break; - case 2: - if (!streq(token, "efg")) return FALSE; - break; - default: - return FALSE; - } - i++; - } - if (i != 3) - { - return FALSE; - } - enumerator->destroy(enumerator); - } - - for (num = 0; num < countof(tests2); num++) - { - i = 0; - enumerator = enumerator_create_token(tests2[num].string, - tests2[num].sep, tests2[num].trim); - while (enumerator->enumerate(enumerator, &token)) - { - switch (i) - { - case 0: - if (!streq(token, "a")) return FALSE; - break; - case 1: - if (!streq(token, "b")) return FALSE; - break; - case 2: - if (!streq(token, "c")) return FALSE; - break; - default: - return FALSE; - } - i++; - } - if (i != 3) - { - return FALSE; - } - enumerator->destroy(enumerator); - } - - return TRUE; -} - From 0298be570504948754444a3c287c622d9c566e33 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 14:52:33 +0100 Subject: [PATCH 08/48] Converted tests for identification_t --- src/libcharon/plugins/unit_tester/Makefile.am | 1 - src/libcharon/plugins/unit_tester/tests.h | 4 - .../plugins/unit_tester/tests/test_id.c | 249 ------------------ src/libstrongswan/tests/Makefile.am | 3 +- src/libstrongswan/tests/test_identification.c | 211 +++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 7 files changed, 215 insertions(+), 255 deletions(-) delete mode 100644 src/libcharon/plugins/unit_tester/tests/test_id.c create mode 100644 src/libstrongswan/tests/test_identification.c diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index ec98dc689..84e717034 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -23,7 +23,6 @@ libstrongswan_unit_tester_la_SOURCES = \ tests/test_chunk.c \ tests/test_pool.c \ tests/test_agent.c \ - tests/test_id.c \ tests/test_hashtable.c libstrongswan_unit_tester_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h index bc7e174f3..fc7761bb5 100644 --- a/src/libcharon/plugins/unit_tester/tests.h +++ b/src/libcharon/plugins/unit_tester/tests.h @@ -31,9 +31,5 @@ DEFINE_TEST("Mediation database key fetch", test_med_db, FALSE) DEFINE_TEST("Base64 converter", test_chunk_base64, FALSE) DEFINE_TEST("IP pool", test_pool, FALSE) DEFINE_TEST("SSH agent", test_agent, FALSE) -DEFINE_TEST("ID parts", test_id_parts, FALSE) -DEFINE_TEST("ID wildcards", test_id_wildcards, FALSE) -DEFINE_TEST("ID equals", test_id_equals, FALSE) -DEFINE_TEST("ID matches", test_id_matches, FALSE) /** @}*/ diff --git a/src/libcharon/plugins/unit_tester/tests/test_id.c b/src/libcharon/plugins/unit_tester/tests/test_id.c deleted file mode 100644 index 868a2ca8b..000000000 --- a/src/libcharon/plugins/unit_tester/tests/test_id.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * 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 2 of the License, or (at your - * option) any later version. See . - * - * 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. - */ - -#include - -/******************************************************************************* - * identification part enumeration test - ******************************************************************************/ -bool test_id_parts() -{ - identification_t *id; - enumerator_t *enumerator; - id_part_t part; - chunk_t data; - int i = 0; - - id = identification_create_from_string("C=CH, O=strongSwan, CN=tester"); - - enumerator = id->create_part_enumerator(id); - while (enumerator->enumerate(enumerator, &part, &data)) - { - switch (i++) - { - case 0: - if (part != ID_PART_RDN_C || - !chunk_equals(data, chunk_create("CH", 2))) - { - return FALSE; - } - break; - case 1: - if (part != ID_PART_RDN_O || - !chunk_equals(data, chunk_create("strongSwan", 10))) - { - return FALSE; - } - break; - case 2: - if (part != ID_PART_RDN_CN || - !chunk_equals(data, chunk_create("tester", 6))) - { - return FALSE; - } - break; - default: - return FALSE; - } - } - if (i < 3) - { - return FALSE; - } - enumerator->destroy(enumerator); - id->destroy(id); - return TRUE; -} - -/******************************************************************************* - * identification contains_wildcards() test - ******************************************************************************/ - -static bool test_id_wildcards_has(char *string) -{ - identification_t *id; - bool contains; - - id = identification_create_from_string(string); - contains = id->contains_wildcards(id); - id->destroy(id); - return contains; -} - -bool test_id_wildcards() -{ - if (!test_id_wildcards_has("C=*, O=strongSwan, CN=gw")) - { - return FALSE; - } - if (!test_id_wildcards_has("C=CH, O=strongSwan, CN=*")) - { - return FALSE; - } - if (test_id_wildcards_has("C=**, O=a*, CN=*a")) - { - return FALSE; - } - if (!test_id_wildcards_has("*@strongswan.org")) - { - return FALSE; - } - if (!test_id_wildcards_has("*.strongswan.org")) - { - return FALSE; - } - return TRUE; -} - -/******************************************************************************* - * identification equals test - ******************************************************************************/ - -static bool test_id_equals_one(identification_t *a, char *b_str) -{ - identification_t *b; - bool equals; - - b = identification_create_from_string(b_str); - equals = a->equals(a, b); - b->destroy(b); - return equals; -} - -bool test_id_equals() -{ - identification_t *a; - chunk_t encoding, fuzzed; - int i; - - a = identification_create_from_string( - "C=CH, E=martin@strongswan.org, CN=martin"); - - if (!test_id_equals_one(a, "C=CH, E=martin@strongswan.org, CN=martin")) - { - return FALSE; - } - if (!test_id_equals_one(a, "C=ch, E=martin@STRONGSWAN.ORG, CN=Martin")) - { - return FALSE; - } - if (test_id_equals_one(a, "C=CN, E=martin@strongswan.org, CN=martin")) - { - return FALSE; - } - if (test_id_equals_one(a, "E=martin@strongswan.org, C=CH, CN=martin")) - { - return FALSE; - } - if (test_id_equals_one(a, "E=martin@strongswan.org, C=CH, CN=martin")) - { - return FALSE; - } - encoding = chunk_clone(a->get_encoding(a)); - a->destroy(a); - - /* simple fuzzing, increment each byte of encoding */ - for (i = 0; i < encoding.len; i++) - { - if (i == 11 || i == 30 || i == 62) - { /* skip ASN.1 type fields, as equals() handles them graceful */ - continue; - } - fuzzed = chunk_clone(encoding); - fuzzed.ptr[i]++; - a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); - if (test_id_equals_one(a, "C=CH, E=martin@strongswan.org, CN=martin")) - { - return FALSE; - } - a->destroy(a); - free(fuzzed.ptr); - } - - /* and decrement each byte of encoding */ - for (i = 0; i < encoding.len; i++) - { - if (i == 11 || i == 30 || i == 62) - { - continue; - } - fuzzed = chunk_clone(encoding); - fuzzed.ptr[i]--; - a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); - if (test_id_equals_one(a, "C=CH, E=martin@strongswan.org, CN=martin")) - { - return FALSE; - } - a->destroy(a); - free(fuzzed.ptr); - } - free(encoding.ptr); - return TRUE; -} - -/******************************************************************************* - * identification matches test - ******************************************************************************/ - -static id_match_t test_id_matches_one(identification_t *a, char *b_str) -{ - identification_t *b; - id_match_t match; - - b = identification_create_from_string(b_str); - match = a->matches(a, b); - b->destroy(b); - return match; -} - -bool test_id_matches() -{ - identification_t *a; - - a = identification_create_from_string( - "C=CH, E=martin@strongswan.org, CN=martin"); - - if (test_id_matches_one(a, "C=CH, E=martin@strongswan.org, CN=martin") - != ID_MATCH_PERFECT) - { - return FALSE; - } - if (test_id_matches_one(a, "C=CH, E=*, CN=martin") != ID_MATCH_ONE_WILDCARD) - { - return FALSE; - } - if (test_id_matches_one(a, "C=CH, E=*, CN=*") != ID_MATCH_ONE_WILDCARD - 1) - { - return FALSE; - } - if (test_id_matches_one(a, "C=*, E=*, CN=*") != ID_MATCH_ONE_WILDCARD - 2) - { - return FALSE; - } - if (test_id_matches_one(a, "C=*, E=*, CN=*, O=BADInc") != ID_MATCH_NONE) - { - return FALSE; - } - if (test_id_matches_one(a, "C=*, E=*") != ID_MATCH_NONE) - { - return FALSE; - } - if (test_id_matches_one(a, "C=*, E=a@b.c, CN=*") != ID_MATCH_NONE) - { - return FALSE; - } - a->destroy(a); - return TRUE; -} diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 0fd404014..e389bc3c4 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -4,7 +4,8 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ - test_linked_list.c test_enumerator.c test_linked_list_enumerator.c + test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ + test_identification.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_identification.c b/src/libstrongswan/tests/test_identification.c new file mode 100644 index 000000000..fd6177f34 --- /dev/null +++ b/src/libstrongswan/tests/test_identification.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include + +/******************************************************************************* + * equals + */ + +static bool id_equals(identification_t *a, char *b_str) +{ + identification_t *b; + bool equals; + + b = identification_create_from_string(b_str); + equals = a->equals(a, b); + b->destroy(b); + return equals; +} + +START_TEST(test_equals) +{ + identification_t *a; + chunk_t encoding, fuzzed; + int i; + + a = identification_create_from_string( + "C=CH, E=martin@strongswan.org, CN=martin"); + + ck_assert(id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); + ck_assert(id_equals(a, "C=ch, E=martin@STRONGSWAN.ORG, CN=Martin")); + ck_assert(!id_equals(a, "C=CN, E=martin@strongswan.org, CN=martin")); + ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin")); + ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin")); + + encoding = chunk_clone(a->get_encoding(a)); + a->destroy(a); + + /* simple fuzzing, increment each byte of encoding */ + for (i = 0; i < encoding.len; i++) + { + if (i == 11 || i == 30 || i == 62) + { /* skip ASN.1 type fields, as equals() handles them graceful */ + continue; + } + fuzzed = chunk_clone(encoding); + fuzzed.ptr[i]++; + a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); + ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); + a->destroy(a); + free(fuzzed.ptr); + } + + /* and decrement each byte of encoding */ + for (i = 0; i < encoding.len; i++) + { + if (i == 11 || i == 30 || i == 62) + { + continue; + } + fuzzed = chunk_clone(encoding); + fuzzed.ptr[i]--; + a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); + ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); + a->destroy(a); + free(fuzzed.ptr); + } + free(encoding.ptr); +} +END_TEST + +/******************************************************************************* + * matches + */ + +static bool id_matches(identification_t *a, char *b_str, id_match_t expected) +{ + identification_t *b; + id_match_t match; + + b = identification_create_from_string(b_str); + match = a->matches(a, b); + b->destroy(b); + return match == expected; +} + +START_TEST(test_matches) +{ + identification_t *a; + + a = identification_create_from_string("C=CH, E=martin@strongswan.org, CN=martin"); + + ck_assert(id_matches(a, "C=CH, E=martin@strongswan.org, CN=martin", ID_MATCH_PERFECT)); + ck_assert(id_matches(a, "C=CH, E=*, CN=martin", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "C=CH, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 1)); + ck_assert(id_matches(a, "C=*, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 2)); + ck_assert(id_matches(a, "C=*, E=*, CN=*, O=BADInc", ID_MATCH_NONE)); + ck_assert(id_matches(a, "C=*, E=*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "C=*, E=a@b.c, CN=*", ID_MATCH_NONE)); + + a->destroy(a); +} +END_TEST + +/******************************************************************************* + * identification part enumeration + */ + +START_TEST(test_parts) +{ + identification_t *id; + enumerator_t *enumerator; + id_part_t part; + chunk_t data; + int i = 0; + + id = identification_create_from_string("C=CH, O=strongSwan, CN=tester"); + + enumerator = id->create_part_enumerator(id); + while (enumerator->enumerate(enumerator, &part, &data)) + { + switch (i++) + { + case 0: + ck_assert(part == ID_PART_RDN_C && + chunk_equals(data, chunk_create("CH", 2))); + break; + case 1: + ck_assert(part == ID_PART_RDN_O && + chunk_equals(data, chunk_from_str("strongSwan"))); + break; + case 2: + ck_assert(part == ID_PART_RDN_CN && + chunk_equals(data, chunk_from_str("tester"))); + break; + default: + fail("unexpected identification part %d", part); + } + } + ck_assert_int_eq(i, 3); + enumerator->destroy(enumerator); + id->destroy(id); +} +END_TEST + +/******************************************************************************* + * wildcards + */ + +static bool id_contains_wildcards(char *string) +{ + identification_t *id; + bool contains; + + id = identification_create_from_string(string); + contains = id->contains_wildcards(id); + id->destroy(id); + return contains; +} + +START_TEST(test_contains_wildcards) +{ + ck_assert(id_contains_wildcards("%any")); + ck_assert(id_contains_wildcards("C=*, O=strongSwan, CN=gw")); + ck_assert(id_contains_wildcards("C=CH, O=strongSwan, CN=*")); + ck_assert(id_contains_wildcards("*@strongswan.org")); + ck_assert(id_contains_wildcards("*.strongswan.org")); + ck_assert(!id_contains_wildcards("C=**, O=a*, CN=*a")); +} +END_TEST + +Suite *identification_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("identification"); + + tc = tcase_create("equals"); + tcase_add_test(tc, test_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("matches"); + tcase_add_test(tc, test_matches); + suite_add_tcase(s, tc); + + tc = tcase_create("part enumeration"); + tcase_add_test(tc, test_parts); + suite_add_tcase(s, tc); + + tc = tcase_create("wildcards"); + tcase_add_test(tc, test_contains_wildcards); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index dab532e3b..7d5c50288 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -35,6 +35,7 @@ int main() srunner_add_suite(sr, enumerator_suite_create()); srunner_add_suite(sr, linked_list_suite_create()); srunner_add_suite(sr, linked_list_enumerator_suite_create()); + srunner_add_suite(sr, identification_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index e297c88bc..71deba127 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -21,5 +21,6 @@ Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); +Suite *identification_suite_create(); #endif /** TEST_RUNNER_H_ */ From e09461bf77df9db40f15d9bcf1a64a959e8d7fb6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 16:38:27 +0100 Subject: [PATCH 09/48] Converted and added tests for hashtable_t --- src/libcharon/plugins/unit_tester/Makefile.am | 3 +- src/libcharon/plugins/unit_tester/tests.h | 1 - .../unit_tester/tests/test_hashtable.c | 111 ------- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_hashtable.c | 295 ++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 7 files changed, 299 insertions(+), 115 deletions(-) delete mode 100644 src/libcharon/plugins/unit_tester/tests/test_hashtable.c create mode 100644 src/libstrongswan/tests/test_hashtable.c diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index 84e717034..b597b928b 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -22,7 +22,6 @@ libstrongswan_unit_tester_la_SOURCES = \ tests/test_med_db.c \ tests/test_chunk.c \ tests/test_pool.c \ - tests/test_agent.c \ - tests/test_hashtable.c + tests/test_agent.c libstrongswan_unit_tester_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h index fc7761bb5..527bb2572 100644 --- a/src/libcharon/plugins/unit_tester/tests.h +++ b/src/libcharon/plugins/unit_tester/tests.h @@ -18,7 +18,6 @@ * @{ @ingroup unit_tester */ -DEFINE_TEST("hashtable_t->remove_at()", test_hashtable_remove_at, FALSE) DEFINE_TEST("auth cfg", test_auth_cfg, FALSE) DEFINE_TEST("CURL get", test_curl_get, FALSE) DEFINE_TEST("MySQL operations", test_mysql, FALSE) diff --git a/src/libcharon/plugins/unit_tester/tests/test_hashtable.c b/src/libcharon/plugins/unit_tester/tests/test_hashtable.c deleted file mode 100644 index 5513f6707..000000000 --- a/src/libcharon/plugins/unit_tester/tests/test_hashtable.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * 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 2 of the License, or (at your - * option) any later version. See . - * - * 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. - */ - -#include -#include - -static u_int hash(char *key) -{ - return chunk_hash(chunk_create(key, strlen(key))); -} - -static u_int equals(char *key1, char *key2) -{ - return streq(key1, key2); -} - -/** - * Test the remove_at method - */ -bool test_hashtable_remove_at() -{ - char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key; - char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; - enumerator_t *enumerator; - hashtable_t *ht = hashtable_create((hashtable_hash_t)hash, - (hashtable_equals_t)equals, 0); - - ht->put(ht, k1, v1); - ht->put(ht, k2, v2); - ht->put(ht, k3, v3); - - if (ht->get_count(ht) != 3) - { - return FALSE; - } - - enumerator = ht->create_enumerator(ht); - while (enumerator->enumerate(enumerator, &key, &value)) - { - if (streq(key, k2)) - { - ht->remove_at(ht, enumerator); - } - } - enumerator->destroy(enumerator); - - if (ht->get_count(ht) != 2) - { - return FALSE; - } - - if (ht->get(ht, k1) == NULL || - ht->get(ht, k3) == NULL) - { - return FALSE; - } - - if (ht->get(ht, k2) != NULL) - { - return FALSE; - } - - ht->put(ht, k2, v2); - - if (ht->get_count(ht) != 3) - { - return FALSE; - } - - if (ht->get(ht, k1) == NULL || - ht->get(ht, k2) == NULL || - ht->get(ht, k3) == NULL) - { - return FALSE; - } - - enumerator = ht->create_enumerator(ht); - while (enumerator->enumerate(enumerator, &key, &value)) - { - ht->remove_at(ht, enumerator); - } - enumerator->destroy(enumerator); - - if (ht->get_count(ht) != 0) - { - return FALSE; - } - - if (ht->get(ht, k1) != NULL || - ht->get(ht, k2) != NULL || - ht->get(ht, k3) != NULL) - { - return FALSE; - } - - ht->destroy(ht); - - return TRUE; -} diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index e389bc3c4..45aab8736 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,7 +5,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_identification.c + test_hashtable.c test_identification.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_hashtable.c b/src/libstrongswan/tests/test_hashtable.c new file mode 100644 index 000000000..802016f59 --- /dev/null +++ b/src/libstrongswan/tests/test_hashtable.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2010-2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include +#include + +/******************************************************************************* + * string hash table functions + */ + +static u_int hash(char *key) +{ + return chunk_hash(chunk_from_str(key)); +} + +static bool equals(char *key1, char *key2) +{ + return streq(key1, key2); +} + +/******************************************************************************* + * test fixture + */ + +static hashtable_t *ht; + +static void setup_ht() +{ + ht = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 0); + ck_assert_int_eq(ht->get_count(ht), 0); +} + +static void teardown_ht() +{ + ht->destroy(ht); +} + +/******************************************************************************* + * put/get + */ + +START_TEST(test_put_get) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3"; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + + value = ht->put(ht, k1, v1); + ck_assert_int_eq(ht->get_count(ht), 1); + ck_assert(streq(ht->get(ht, k1), v1)); + ck_assert(ht->get(ht, k2) == NULL); + ck_assert(ht->get(ht, k3) == NULL); + ck_assert(value == NULL); + + ht->put(ht, k2, v2); + ht->put(ht, k3, v3); + ck_assert_int_eq(ht->get_count(ht), 3); + ck_assert(streq(ht->get(ht, k1), v1)); + ck_assert(streq(ht->get(ht, k2), v2)); + ck_assert(streq(ht->get(ht, k3), v3)); + + value = ht->put(ht, k2, v1); + ck_assert_int_eq(ht->get_count(ht), 3); + ck_assert(streq(value, v2)); + ck_assert(streq(ht->get(ht, k2), v1)); +} +END_TEST + +/******************************************************************************* + * get_match + */ + +static u_int hash_match(char *key) +{ + return chunk_hash(chunk_create(key, 4)); +} + +static bool equal_match(char *key1, char *key2) +{ + if (!strneq(key1, key2, 4)) + { + return FALSE; + } + /* look for an item with a key < than what we look for */ + return strcmp(key1, key2) >= 0; +} + +START_TEST(test_get_match) +{ + char *k1 = "key1_a", *k2 = "key2", *k3 = "key1_b", *k4 = "key1_c"; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + + ht = hashtable_create((hashtable_hash_t)hash_match, + (hashtable_equals_t)equals, 0); + + ht->put(ht, k1, v1); + ht->put(ht, k2, v2); + value = ht->put(ht, k3, v3); + ck_assert_int_eq(ht->get_count(ht), 3); + ck_assert(streq(ht->get(ht, k1), v1)); + ck_assert(streq(ht->get(ht, k2), v2)); + ck_assert(streq(ht->get(ht, k3), v3)); + ck_assert(value == NULL); + + value = ht->get_match(ht, k1, (hashtable_equals_t)equal_match); + ck_assert(value != NULL); + ck_assert(streq(value, v1)); + value = ht->get_match(ht, k2, (hashtable_equals_t)equal_match); + ck_assert(value != NULL); + ck_assert(streq(value, v2)); + value = ht->get_match(ht, k3, (hashtable_equals_t)equal_match); + ck_assert(value != NULL); + ck_assert(streq(value, v1)); + value = ht->get_match(ht, k4, (hashtable_equals_t)equal_match); + ck_assert(value != NULL); + ck_assert(streq(value, v1)); + + ht->destroy(ht); +} +END_TEST + +/******************************************************************************* + * remove + */ + +START_TEST(test_remove) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3"; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + + ht->put(ht, k1, v1); + ht->put(ht, k2, v2); + ht->put(ht, k3, v3); + + value = ht->remove(ht, k2); + ck_assert_int_eq(ht->get_count(ht), 2); + ck_assert(streq(ht->get(ht, k1), v1)); + ck_assert(streq(ht->get(ht, k3), v3)); + ck_assert(streq(value, v2)); + ck_assert(ht->get(ht, k2) == NULL); + + value = ht->remove(ht, k2); + ck_assert_int_eq(ht->get_count(ht), 2); + ck_assert(value == NULL); + + value = ht->remove(ht, k1); + value = ht->remove(ht, k3); + ck_assert_int_eq(ht->get_count(ht), 0); + ck_assert(ht->get(ht, k1) == NULL); + ck_assert(ht->get(ht, k2) == NULL); + ck_assert(ht->get(ht, k3) == NULL); +} +END_TEST + +/******************************************************************************* + * enumerator + */ + +START_TEST(test_enumerator) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + enumerator_t *enumerator; + int count; + + ht->put(ht, k1, v1); + ht->put(ht, k2, v2); + ht->put(ht, k3, v3); + + count = 0; + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &key, &value)) + { + ck_assert(streq(key, k1) || streq(key, k2) || streq(key, k3)); + ck_assert(streq(value, v1) || streq(value, v2) || streq(value, v3)); + ck_assert(!streq(key, k1) || streq(value, v1)); + ck_assert(!streq(key, k2) || streq(value, v2)); + ck_assert(!streq(key, k3) || streq(value, v3)); + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 3); + + value = ht->remove(ht, k1); + value = ht->remove(ht, k2); + value = ht->remove(ht, k3); + + count = 0; + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &key, &value)) + { + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 0); +} +END_TEST + +/******************************************************************************* + * remove_at + */ + +START_TEST(test_remove_at) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + enumerator_t *enumerator; + + ht->put(ht, k1, v1); + ht->put(ht, k2, v2); + ht->put(ht, k3, v3); + + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &key, &value)) + { + if (streq(key, k2)) + { + ht->remove_at(ht, enumerator); + } + } + enumerator->destroy(enumerator); + + ck_assert_int_eq(ht->get_count(ht), 2); + ck_assert(ht->get(ht, k1) != NULL); + ck_assert(ht->get(ht, k3) != NULL); + ck_assert(ht->get(ht, k2) == NULL); + + ht->put(ht, k2, v2); + + ck_assert_int_eq(ht->get_count(ht), 3); + ck_assert(ht->get(ht, k1) != NULL); + ck_assert(ht->get(ht, k2) != NULL); + ck_assert(ht->get(ht, k3) != NULL); + + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &key, &value)) + { + ht->remove_at(ht, enumerator); + } + enumerator->destroy(enumerator); + + ck_assert_int_eq(ht->get_count(ht), 0); + ck_assert(ht->get(ht, k1) == NULL); + ck_assert(ht->get(ht, k2) == NULL); + ck_assert(ht->get(ht, k3) == NULL); +} +END_TEST + +Suite *hashtable_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("hashtable"); + + tc = tcase_create("put/get"); + tcase_add_checked_fixture(tc, setup_ht, teardown_ht); + tcase_add_test(tc, test_put_get); + suite_add_tcase(s, tc); + + tc = tcase_create("get_match"); + tcase_add_test(tc, test_get_match); + suite_add_tcase(s, tc); + + tc = tcase_create("remove"); + tcase_add_checked_fixture(tc, setup_ht, teardown_ht); + tcase_add_test(tc, test_remove); + suite_add_tcase(s, tc); + + tc = tcase_create("enumerator"); + tcase_add_checked_fixture(tc, setup_ht, teardown_ht); + tcase_add_test(tc, test_enumerator); + suite_add_tcase(s, tc); + + tc = tcase_create("remove_at"); + tcase_add_checked_fixture(tc, setup_ht, teardown_ht); + tcase_add_test(tc, test_remove_at); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 7d5c50288..114ba39e1 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -35,6 +35,7 @@ int main() srunner_add_suite(sr, enumerator_suite_create()); srunner_add_suite(sr, linked_list_suite_create()); srunner_add_suite(sr, linked_list_enumerator_suite_create()); + srunner_add_suite(sr, hashtable_suite_create()); srunner_add_suite(sr, identification_suite_create()); srunner_run_all(sr, CK_NORMAL); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 71deba127..490bf54f8 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -21,6 +21,7 @@ Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); +Suite *hashtable_suite_create(); Suite *identification_suite_create(); #endif /** TEST_RUNNER_H_ */ From 4e67f1952881e890fbc9e8363f827f24899464cb Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 16:39:44 +0100 Subject: [PATCH 10/48] Converted tests for chunk_t --- src/libcharon/plugins/unit_tester/Makefile.am | 1 - src/libcharon/plugins/unit_tester/tests.h | 1 - src/libstrongswan/tests/Makefile.am | 2 +- .../tests/test_chunk.c | 48 +++++++++++-------- src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 6 files changed, 30 insertions(+), 24 deletions(-) rename src/{libcharon/plugins/unit_tester => libstrongswan}/tests/test_chunk.c (74%) diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index b597b928b..db11d934c 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -20,7 +20,6 @@ libstrongswan_unit_tester_la_SOURCES = \ tests/test_rsa_gen.c \ tests/test_cert.c \ tests/test_med_db.c \ - tests/test_chunk.c \ tests/test_pool.c \ tests/test_agent.c diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h index 527bb2572..4fd358e6b 100644 --- a/src/libcharon/plugins/unit_tester/tests.h +++ b/src/libcharon/plugins/unit_tester/tests.h @@ -27,7 +27,6 @@ DEFINE_TEST("RSA key generation", test_rsa_gen, FALSE) DEFINE_TEST("RSA subjectPublicKeyInfo loading", test_rsa_load_any, FALSE) DEFINE_TEST("X509 certificate", test_cert_x509, FALSE) DEFINE_TEST("Mediation database key fetch", test_med_db, FALSE) -DEFINE_TEST("Base64 converter", test_chunk_base64, FALSE) DEFINE_TEST("IP pool", test_pool, FALSE) DEFINE_TEST("SSH agent", test_agent, FALSE) diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 45aab8736..bb1ce91a7 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,7 +5,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_hashtable.c test_identification.c + test_chunk.c test_hashtable.c test_identification.c test_runner_CFLAGS = \ diff --git a/src/libcharon/plugins/unit_tester/tests/test_chunk.c b/src/libstrongswan/tests/test_chunk.c similarity index 74% rename from src/libcharon/plugins/unit_tester/tests/test_chunk.c rename to src/libstrongswan/tests/test_chunk.c index 2e0905b2c..151775ef7 100644 --- a/src/libcharon/plugins/unit_tester/tests/test_chunk.c +++ b/src/libstrongswan/tests/test_chunk.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2013 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -13,13 +14,16 @@ * for more details. */ -#include -#include + +#include + +#include /******************************************************************************* - * Base64 encoding/decoding test - ******************************************************************************/ -bool test_chunk_base64() + * BASE64 encoding test + */ + +START_TEST(test_base64) { /* test vectors from RFC4648: * @@ -31,7 +35,6 @@ bool test_chunk_base64() * BASE64("fooba") = "Zm9vYmE=" * BASE64("foobar") = "Zm9vYmFy" */ - typedef struct { char *in; char *out; @@ -53,13 +56,7 @@ bool test_chunk_base64() chunk_t out; out = chunk_to_base64(chunk_create(test[i].in, strlen(test[i].in)), NULL); - - if (!streq(out.ptr, test[i].out)) - { - DBG1(DBG_CFG, "base64 conversion error - should %s, is %s", - test[i].out, out.ptr); - return FALSE; - } + ck_assert_str_eq(out.ptr, test[i].out); free(out.ptr); } @@ -68,15 +65,24 @@ bool test_chunk_base64() chunk_t out; out = chunk_from_base64(chunk_create(test[i].out, strlen(test[i].out)), NULL); - - if (!strneq(out.ptr, test[i].in, out.len)) - { - DBG1(DBG_CFG, "base64 conversion error - should %s, is %#B", - test[i].in, &out); - return FALSE; - } + fail_unless(strneq(out.ptr, test[i].in, out.len), + "base64 conversion error - should '%s', is %#B", + test[i].in, &out); free(out.ptr); } - return TRUE; } +END_TEST +Suite *chunk_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("chunk"); + + tc = tcase_create("base64"); + tcase_add_test(tc, test_base64); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 114ba39e1..03287e53c 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -32,6 +32,7 @@ int main() library_init(NULL); sr = srunner_create(NULL); + srunner_add_suite(sr, chunk_suite_create()); srunner_add_suite(sr, enumerator_suite_create()); srunner_add_suite(sr, linked_list_suite_create()); srunner_add_suite(sr, linked_list_enumerator_suite_create()); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 490bf54f8..7593c6aa6 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -18,6 +18,7 @@ #include +Suite *chunk_suite_create(); Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); From 1255de5a2076dc591dfa1ffefffea077bd218319 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 18:18:52 +0100 Subject: [PATCH 11/48] Adding chunk_mac() which calculates a 64-bit MAC using SipHash-2-4 --- src/libstrongswan/tests/test_chunk.c | 113 +++++++++++++++++++++++++ src/libstrongswan/utils/chunk.c | 118 ++++++++++++++++++++++++++- src/libstrongswan/utils/chunk.h | 18 +++- 3 files changed, 246 insertions(+), 3 deletions(-) diff --git a/src/libstrongswan/tests/test_chunk.c b/src/libstrongswan/tests/test_chunk.c index 151775ef7..6ea80b977 100644 --- a/src/libstrongswan/tests/test_chunk.c +++ b/src/libstrongswan/tests/test_chunk.c @@ -73,6 +73,115 @@ START_TEST(test_base64) } END_TEST +/******************************************************************************* + * test for chunk_mac(), i.e. SipHash-2-4 + */ + +/** + * SipHash-2-4 output with + * k = 00 01 02 ... + * and + * in = (empty string) + * in = 00 (1 byte) + * in = 00 01 (2 bytes) + * in = 00 01 02 (3 bytes) + * ... + * in = 00 01 02 ... 3e (63 bytes) + */ +static const u_char sip_vectors[64][8] = +{ + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } +}; + +START_TEST(test_chunk_mac) +{ + chunk_t in; + u_char key[16]; + u_int64_t out; + int i, count; + + count = countof(sip_vectors); + in = chunk_alloca(count); + + for (i = 0; i < 16; ++i) + { + key[i] = i; + } + + for (i = 0; i < count; ++i) + { + in.ptr[i] = i; + in.len = i; + out = chunk_mac(in, key); + fail_unless(memeq(&out, sip_vectors[i], 8), + "test vector failed for %d bytes", i); + } +} +END_TEST + Suite *chunk_suite_create() { Suite *s; @@ -84,5 +193,9 @@ Suite *chunk_suite_create() tcase_add_test(tc, test_base64); suite_add_tcase(s, tc); + tc = tcase_create("chunk_mac"); + tcase_add_test(tc, test_chunk_mac); + suite_add_tcase(s, tc); + return s; } diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index d7f1c31d9..ca277dac6 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2013 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -578,6 +578,122 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace) return printable; } +/** + * Helper functions for chunk_mac() + */ +static inline u_int64_t sipget(u_char *in) +{ + u_int64_t v = 0; + int i; + + for (i = 0; i < 64; i += 8, ++in) + { + v |= ((u_int64_t)*in) << i; + } + return v; +} + +static inline u_int64_t siprotate(u_int64_t v, int shift) +{ + return (v << shift) | (v >> (64 - shift)); +} + +static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2, + u_int64_t *v3) +{ + *v0 += *v1; + *v1 = siprotate(*v1, 13); + *v1 ^= *v0; + *v0 = siprotate(*v0, 32); + + *v2 += *v3; + *v3 = siprotate(*v3, 16); + *v3 ^= *v2; + + *v2 += *v1; + *v1 = siprotate(*v1, 17); + *v1 ^= *v2; + *v2 = siprotate(*v2, 32); + + *v0 += *v3; + *v3 = siprotate(*v3, 21); + *v3 ^= *v0; +} + +static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2, + u_int64_t *v3, u_int64_t m) +{ + *v3 ^= m; + sipround(v0, v1, v2, v3); + sipround(v0, v1, v2, v3); + *v0 ^= m; +} + +static inline u_int64_t siplast(size_t len, u_char *pos) +{ + u_int64_t b; + int rem = len & 7; + + b = ((u_int64_t)len) << 56; + switch (rem) + { + case 7: + b |= ((u_int64_t)pos[6]) << 48; + case 6: + b |= ((u_int64_t)pos[5]) << 40; + case 5: + b |= ((u_int64_t)pos[4]) << 32; + case 4: + b |= ((u_int64_t)pos[3]) << 24; + case 3: + b |= ((u_int64_t)pos[2]) << 16; + case 2: + b |= ((u_int64_t)pos[1]) << 8; + case 1: + b |= ((u_int64_t)pos[0]); + break; + case 0: + break; + } + return b; +} + +/** + * Described in header. + */ +u_int64_t chunk_mac(chunk_t chunk, u_char *key) +{ + u_int64_t v0, v1, v2, v3, k0, k1, m; + size_t len = chunk.len; + u_char *pos = chunk.ptr, *end; + + end = chunk.ptr + len - (len % 8); + + k0 = sipget(key); + k1 = sipget(key + 8); + + v0 = k0 ^ 0x736f6d6570736575ULL; + v1 = k1 ^ 0x646f72616e646f6dULL; + v2 = k0 ^ 0x6c7967656e657261ULL; + v3 = k1 ^ 0x7465646279746573ULL; + + /* compression with c = 2 */ + for (; pos != end; pos += 8) + { + m = sipget(pos); + sipcompress(&v0, &v1, &v2, &v3, m); + } + sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos)); + + /* finalization with d = 4 */ + v2 ^= 0xff; + sipround(&v0, &v1, &v2, &v3); + sipround(&v0, &v1, &v2, &v3); + sipround(&v0, &v1, &v2, &v3); + sipround(&v0, &v1, &v2, &v3); + return v0 ^ v1 ^ v2 ^ v3; +} + /** * Described in header. * diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index bc14b7394..b28ff12b8 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2013 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -301,7 +301,7 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace); /** * Computes a 32 bit hash of the given chunk. - * Note: This hash is only intended for hash tables not for cryptographic purposes. + * @note This hash is only intended for hash tables not for cryptographic purposes. */ u_int32_t chunk_hash(chunk_t chunk); @@ -310,6 +310,20 @@ u_int32_t chunk_hash(chunk_t chunk); */ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash); +/** + * Computes a quick MAC from the given chunk and key using SipHash. + * + * The key must have a length of 128-bit (16 bytes). + * + * @note While SipHash has strong features using it for cryptographic purposes + * is not recommended (in particular because of the rather short output size). + * + * @param chunk data to process + * @param key key to use + * @return MAC for given input and key + */ +u_int64_t chunk_mac(chunk_t chunk, u_char *key); + /** * printf hook function for chunk_t. * From d1953fe403a91d6f7a08fd4cdd0b01cf7106733d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 19:24:24 +0100 Subject: [PATCH 12/48] Replace chunk_hash() with output from chunk_mac() The quality is way better, the calculation is a bit slower though. The key is statically initialized to zero, which will be changed later to prevent hash flooding. --- src/libstrongswan/utils/chunk.c | 100 ++++++++------------------------ src/libstrongswan/utils/chunk.h | 8 +++ 2 files changed, 32 insertions(+), 76 deletions(-) diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index ca277dac6..9033cbdaf 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -24,16 +24,6 @@ #include "chunk.h" #include "debug.h" -/* required for chunk_hash */ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) -#define get16bits(d) (*((const u_int16_t*)(d))) -#endif -#if !defined (get16bits) -#define get16bits(d) ((((u_int32_t)(((const u_int8_t*)(d))[1])) << 8)\ - + (u_int32_t)(((const u_int8_t*)(d))[0]) ) -#endif - /** * Empty chunk. */ @@ -659,11 +649,11 @@ static inline u_int64_t siplast(size_t len, u_char *pos) } /** - * Described in header. + * Caculate SipHash-2-4 with an optional first block given as argument. */ -u_int64_t chunk_mac(chunk_t chunk, u_char *key) +static u_int64_t chunk_mac_inc(chunk_t chunk, u_char *key, u_int64_t m) { - u_int64_t v0, v1, v2, v3, k0, k1, m; + u_int64_t v0, v1, v2, v3, k0, k1; size_t len = chunk.len; u_char *pos = chunk.ptr, *end; @@ -677,6 +667,11 @@ u_int64_t chunk_mac(chunk_t chunk, u_char *key) v2 = k0 ^ 0x6c7967656e657261ULL; v3 = k1 ^ 0x7465646279746573ULL; + if (m) + { + sipcompress(&v0, &v1, &v2, &v3, m); + } + /* compression with c = 2 */ for (; pos != end; pos += 8) { @@ -696,71 +691,24 @@ u_int64_t chunk_mac(chunk_t chunk, u_char *key) /** * Described in header. - * - * The implementation is based on Paul Hsieh's SuperFastHash: - * http://www.azillionmonkeys.com/qed/hash.html + */ +u_int64_t chunk_mac(chunk_t chunk, u_char *key) +{ + return chunk_mac_inc(chunk, key, 0); +} + +/** + * Key used for chunk_hash. + */ +static u_char key[16]; + +/** + * Described in header. */ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash) { - u_char *data = chunk.ptr; - size_t len = chunk.len; - u_int32_t tmp; - int rem; - - if (!len || data == NULL) - { - return 0; - } - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (; len > 0; --len) - { - hash += get16bits(data); - tmp = (get16bits(data + 2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2 * sizeof(u_int16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) - { - case 3: - { - hash += get16bits(data); - hash ^= hash << 16; - hash ^= data[sizeof(u_int16_t)] << 18; - hash += hash >> 11; - break; - } - case 2: - { - hash += get16bits(data); - hash ^= hash << 11; - hash += hash >> 17; - break; - } - case 1: - { - hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - break; - } - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; + /* we could use a mac of the previous hash, but this is faster */ + return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash); } /** @@ -768,7 +716,7 @@ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash) */ u_int32_t chunk_hash(chunk_t chunk) { - return chunk_hash_inc(chunk, chunk.len); + return chunk_mac(chunk, key); } /** diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index b28ff12b8..cfda6ee77 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -301,12 +301,20 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace); /** * Computes a 32 bit hash of the given chunk. + * * @note This hash is only intended for hash tables not for cryptographic purposes. + * + * @param chunk data to hash + * @return hash value */ u_int32_t chunk_hash(chunk_t chunk); /** * Incremental version of chunk_hash. Use this to hash two or more chunks. + * + * @param chunk data to hash + * @param hash previous hash value + * @return hash value */ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash); From bed4bc1327a43f8e4c494e7fdf71680ffcaa26f1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 26 Mar 2013 19:25:55 +0100 Subject: [PATCH 13/48] Randomly allocate chunk_hash() key during first use This avoids hash flooding attacks. --- src/libstrongswan/utils/chunk.c | 47 ++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index 9033cbdaf..61c7bd5a5 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -16,9 +16,12 @@ */ #include +#include #include +#include #include #include +#include #include #include "chunk.h" @@ -698,15 +701,56 @@ u_int64_t chunk_mac(chunk_t chunk, u_char *key) } /** - * Key used for chunk_hash. + * Secret key allocated randomly during first use. */ static u_char key[16]; +/** + * Only allocate the key once + */ +static pthread_once_t key_allocated = PTHREAD_ONCE_INIT; + +/** + * Allocate a key on first use, we do this manually to avoid dependencies on + * plugins. + */ +static void allocate_key() +{ + ssize_t len; + size_t done = 0; + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if (fd >= 0) + { + while (done < sizeof(key)) + { + len = read(fd, key + done, sizeof(key) - done); + if (len < 0) + { + break; + } + done += len; + } + close(fd); + } + /* on error we use random() to generate the key (better than nothing) */ + if (done < sizeof(key)) + { + srandom(time(NULL) + getpid()); + for (; done < sizeof(key); done++) + { + key[done] = (u_char)random(); + } + } +} + /** * Described in header. */ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash) { + pthread_once(&key_allocated, allocate_key); /* we could use a mac of the previous hash, but this is faster */ return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash); } @@ -716,6 +760,7 @@ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash) */ u_int32_t chunk_hash(chunk_t chunk) { + pthread_once(&key_allocated, allocate_key); return chunk_mac(chunk, key); } From de42bf35f9c9f6312a28f8befd8b2a1eaa6d9bfc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 09:16:59 +0100 Subject: [PATCH 14/48] Converted test for recursive mutex_t --- src/libcharon/plugins/unit_tester/Makefile.am | 1 - src/libcharon/plugins/unit_tester/tests.h | 1 - src/libstrongswan/tests/Makefile.am | 3 +- src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + .../tests/test_threading.c} | 63 +++++++++++-------- 6 files changed, 40 insertions(+), 30 deletions(-) rename src/{libcharon/plugins/unit_tester/tests/test_mutex.c => libstrongswan/tests/test_threading.c} (67%) diff --git a/src/libcharon/plugins/unit_tester/Makefile.am b/src/libcharon/plugins/unit_tester/Makefile.am index db11d934c..84628b507 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.am +++ b/src/libcharon/plugins/unit_tester/Makefile.am @@ -16,7 +16,6 @@ libstrongswan_unit_tester_la_SOURCES = \ tests/test_curl.c \ tests/test_mysql.c \ tests/test_sqlite.c \ - tests/test_mutex.c \ tests/test_rsa_gen.c \ tests/test_cert.c \ tests/test_med_db.c \ diff --git a/src/libcharon/plugins/unit_tester/tests.h b/src/libcharon/plugins/unit_tester/tests.h index 4fd358e6b..bcb82c3bd 100644 --- a/src/libcharon/plugins/unit_tester/tests.h +++ b/src/libcharon/plugins/unit_tester/tests.h @@ -22,7 +22,6 @@ DEFINE_TEST("auth cfg", test_auth_cfg, FALSE) DEFINE_TEST("CURL get", test_curl_get, FALSE) DEFINE_TEST("MySQL operations", test_mysql, FALSE) DEFINE_TEST("SQLite operations", test_sqlite, FALSE) -DEFINE_TEST("mutex primitive", test_mutex, FALSE) DEFINE_TEST("RSA key generation", test_rsa_gen, FALSE) DEFINE_TEST("RSA subjectPublicKeyInfo loading", test_rsa_load_any, FALSE) DEFINE_TEST("X509 certificate", test_cert_x509, FALSE) diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index bb1ce91a7..fbceddab5 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,7 +5,8 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_chunk.c test_hashtable.c test_identification.c + test_chunk.c test_hashtable.c test_identification.c \ + test_threading.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 03287e53c..7dc40ff2e 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -38,6 +38,7 @@ int main() srunner_add_suite(sr, linked_list_enumerator_suite_create()); srunner_add_suite(sr, hashtable_suite_create()); srunner_add_suite(sr, identification_suite_create()); + srunner_add_suite(sr, threading_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 7593c6aa6..8ec40a721 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -24,5 +24,6 @@ Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); Suite *hashtable_suite_create(); Suite *identification_suite_create(); +Suite *threading_suite_create(); #endif /** TEST_RUNNER_H_ */ diff --git a/src/libcharon/plugins/unit_tester/tests/test_mutex.c b/src/libstrongswan/tests/test_threading.c similarity index 67% rename from src/libcharon/plugins/unit_tester/tests/test_mutex.c rename to src/libstrongswan/tests/test_threading.c index 77085cb2f..1ffbcb6b0 100644 --- a/src/libcharon/plugins/unit_tester/tests/test_mutex.c +++ b/src/libstrongswan/tests/test_threading.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2013 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -13,41 +14,43 @@ * for more details. */ -#include -#include - -#include +#include #include #include +#include + +/******************************************************************************* + * recursive mutex test + */ + +#define THREADS 20 static mutex_t *mutex; -static int locked = 0; +static pthread_barrier_t mutex_barrier; -static bool failed = FALSE; +static int mutex_locked = 0; -static pthread_barrier_t barrier; - -static void* run(void* null) +static void *mutex_run(void *data) { int i; /* wait for all threads before getting in action */ - pthread_barrier_wait(&barrier); + pthread_barrier_wait(&mutex_barrier); for (i = 0; i < 100; i++) { mutex->lock(mutex); mutex->lock(mutex); mutex->lock(mutex); - locked++; + mutex_locked++; sched_yield(); - if (locked > 1) + if (mutex_locked > 1) { - failed = TRUE; + fail("two threads locked the mutex concurrently"); } - locked--; + mutex_locked--; mutex->unlock(mutex); mutex->unlock(mutex); mutex->unlock(mutex); @@ -55,15 +58,10 @@ static void* run(void* null) return NULL; } -#define THREADS 20 - -/******************************************************************************* - * mutex test - ******************************************************************************/ -bool test_mutex() +START_TEST(test_mutex) { - int i; pthread_t threads[THREADS]; + int i; mutex = mutex_create(MUTEX_TYPE_RECURSIVE); @@ -81,20 +79,31 @@ bool test_mutex() mutex->unlock(mutex); } - pthread_barrier_init(&barrier, NULL, THREADS); - + pthread_barrier_init(&mutex_barrier, NULL, THREADS); for (i = 0; i < THREADS; i++) { - pthread_create(&threads[i], NULL, run, NULL); + pthread_create(&threads[i], NULL, mutex_run, NULL); } for (i = 0; i < THREADS; i++) { pthread_join(threads[i], NULL); } - pthread_barrier_destroy(&barrier); + pthread_barrier_destroy(&mutex_barrier); mutex->destroy(mutex); - - return !failed; } +END_TEST +Suite *threading_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("threading"); + + tc = tcase_create("recursive mutex"); + tcase_add_test(tc, test_mutex); + suite_add_tcase(s, tc); + + return s; +} From 952073b8a71f950365eee3a486c3827d1ae42e9e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 11:24:14 +0100 Subject: [PATCH 15/48] Use proper type for enumerator_t/linked_list_t tests Worked with -O2 but not with -O0. --- src/libstrongswan/tests/test_enumerator.c | 3 ++- .../tests/test_linked_list_enumerator.c | 25 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/libstrongswan/tests/test_enumerator.c b/src/libstrongswan/tests/test_enumerator.c index 882e8cc61..f49ae3380 100644 --- a/src/libstrongswan/tests/test_enumerator.c +++ b/src/libstrongswan/tests/test_enumerator.c @@ -142,7 +142,8 @@ static enumerator_t* create_inner(linked_list_t *outer, void *data) START_TEST(test_nested) { - int round, x; + intptr_t x; + int round; linked_list_t *list, *l1, *l2, *l3; enumerator_t *enumerator; diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c index ed098c07c..fd55eaad1 100644 --- a/src/libstrongswan/tests/test_linked_list_enumerator.c +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -42,7 +42,8 @@ static void teardown_list() START_TEST(test_enumerate) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; round = 1; enumerator = list->create_enumerator(list); @@ -59,7 +60,8 @@ END_TEST START_TEST(test_reset_enumerator) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, &x)) @@ -80,7 +82,8 @@ END_TEST START_TEST(test_has_more) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; round = 1; enumerator = list->create_enumerator(list); @@ -112,7 +115,8 @@ END_TEST START_TEST(test_insert_before) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; round = 1; enumerator = list->create_enumerator(list); @@ -147,7 +151,8 @@ END_TEST START_TEST(test_insert_before_ends) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; enumerator = list->create_enumerator(list); list->insert_before(list, enumerator, (void*)0); @@ -173,7 +178,7 @@ END_TEST START_TEST(test_insert_before_empty) { enumerator_t *enumerator; - int x; + intptr_t x; list->destroy(list); list = linked_list_create(); @@ -199,7 +204,8 @@ END_TEST START_TEST(test_replace) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; round = 1; enumerator = list->create_enumerator(list); @@ -223,7 +229,8 @@ END_TEST START_TEST(test_remove_at) { enumerator_t *enumerator; - int round, x; + intptr_t x; + int round; round = 1; enumerator = list->create_enumerator(list); @@ -255,7 +262,7 @@ END_TEST START_TEST(test_remove_at_ends) { enumerator_t *enumerator; - int x; + intptr_t x; enumerator = list->create_enumerator(list); list->remove_at(list, enumerator); From 1f14b4a1f91f0b76369d3283a6771757e6437a23 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 11:03:56 +0100 Subject: [PATCH 16/48] Add --enable-coverage configure option This configure flag enables lcov [1] coverage generation and is intended to be used with unit tests (--enable-unit-tests is implied). A html coverage report can be generated by issuing the following command in the toplevel build directory: make coverage [1] - http://ltp.sourceforge.net/coverage/lcov.php Based on a patch by Adrian-Ken Rueegsegger. --- .gitignore | 4 ++++ HACKING | 5 ++++- Makefile.am | 28 ++++++++++++++++++++++++++++ configure.in | 25 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 024d9e452..3deb9fdb5 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,7 @@ apidoc/ *.tar.bz2 *.tar.gz .DS_Store +coverage/ +*.gcno +*.gcda +*.gcov \ No newline at end of file diff --git a/HACKING b/HACKING index dbb347e6f..8755fd63f 100644 --- a/HACKING +++ b/HACKING @@ -18,8 +18,11 @@ the code, you need the following tools: - lex/flex - yacc/bison - gperf + + Optionally: - check - - optionally Doxygen + - lcov/genhtml + - Doxygen To check out the master branch, use: diff --git a/Makefile.am b/Makefile.am index 1fc1fcdb3..c7ece4a21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,5 +37,33 @@ Doxyfile : Doxyfile.in apidoc : Doxyfile doxygen +if COVERAGE +cov-reset: + @rm -rf $(top_builddir)/coverage + @find $(top_builddir) -name "*.gcda" -delete + @lcov --zerocounters --directory $(top_builddir) + +cov-report: + @mkdir $(top_builddir)/coverage + lcov -c -o $(top_builddir)/coverage/coverage.info -d $(top_builddir) + genhtml --num-spaces 4 --legend \ + -t "$(PACKAGE_STRING)" \ + -o $(top_builddir)/coverage/html \ + -p `readlink -m $(abs_top_srcdir)`/src \ + $(top_builddir)/coverage/coverage.info + @echo "Coverage Report at $(top_builddir)/coverage/html" >&2 + +coverage: + @$(MAKE) cov-reset + @$(MAKE) check + @$(MAKE) cov-report +else +cov-reset: + +coverage: + @echo "reconfigure with --enable-coverage" +endif + clean-local: + @$(MAKE) cov-reset rm -rf apidoc diff --git a/configure.in b/configure.in index b366a6a0d..6a7f9ffb5 100644 --- a/configure.in +++ b/configure.in @@ -243,6 +243,7 @@ ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.]) ARG_ENABL_SET([unwind-backtraces],[use libunwind to create backtraces for memory leaks and segfaults.]) ARG_ENABL_SET([unit-tests], [enable unit tests using the check test framework.]) +ARG_ENABL_SET([coverage], [enable lcov coverage report generation.]) ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.]) ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.]) @@ -362,6 +363,10 @@ if test x$medcli = xtrue; then mediation=true fi +if test x$coverage = xtrue; then + unit_tests=true +fi + # =========================================== # check required libraries and header files # =========================================== @@ -917,6 +922,25 @@ if test x$unit_tests = xtrue; then AC_SUBST(CHECK_LIBS) fi +if test x$coverage = xtrue; then + AC_PATH_PROG([LCOV], [lcov], [], [$PATH:/bin:/usr/bin:/usr/local/bin]) + if test x$LCOV = x; then + AC_MSG_ERROR([lcov not found]) + fi + AC_PATH_PROG([GENHTML], [genhtml], [], [$PATH:/bin:/usr/bin:/usr/local/bin]) + if test x$GENHTML = x; then + AC_MSG_ERROR([genhtml not found]) + fi + + COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" + COVERAGE_LDFLAGS="-fprofile-arcs" + AC_SUBST(COVERAGE_CFLAGS) + AC_SUBST(COVERAGE_LDFLAGS) + + AC_MSG_NOTICE([coverage enabled, adding "-g -O0" to CFLAGS]) + CFLAGS="${CFLAGS} -g -O0" +fi + # =============================================== # collect plugin list for strongSwan components # =============================================== @@ -1241,6 +1265,7 @@ AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers) AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue) AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes) AM_CONDITIONAL(UNITTESTS, test x$unit_tests = xtrue) +AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue) AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue) AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue) From 01a3ba9e0fdcab937c7e4a37308161ff9952bffc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 11:54:09 +0100 Subject: [PATCH 17/48] Enable coverage report for libstrongswan --- src/libstrongswan/Makefile.am | 3 ++- src/libstrongswan/tests/Makefile.am | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index bde69645f..567bdfe6f 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -87,7 +87,8 @@ AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ -DIPSEC_LIB_DIR=\"${ipseclibdir}\" \ -DPLUGINDIR=\"${plugindir}\" \ --DSTRONGSWAN_CONF=\"${strongswan_conf}\" +-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \ +@COVERAGE_CFLAGS@ if USE_LEAK_DETECTIVE AM_CFLAGS += -DLEAK_DETECTIVE diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index fbceddab5..b0eb0a546 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -13,6 +13,7 @@ test_runner_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ @CHECK_CFLAGS@ +test_runner_LDFLAGS = @COVERAGE_LDFLAGS@ test_runner_LDADD = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ @CHECK_LIBS@ From bc90b3dd0ac8916120ace239367ffc9736220fa4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 13:21:52 +0100 Subject: [PATCH 18/48] Improved test for linked_list_t.insert_before() --- src/libstrongswan/tests/test_linked_list_enumerator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c index fd55eaad1..724aba09e 100644 --- a/src/libstrongswan/tests/test_linked_list_enumerator.c +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -124,7 +124,7 @@ START_TEST(test_insert_before) { ck_assert_int_eq(round, x); round++; - if (x == 2) + if (x == _i) { list->insert_before(list, enumerator, (void*)6); } @@ -134,7 +134,7 @@ START_TEST(test_insert_before) round = 1; while (enumerator->enumerate(enumerator, &x)) { - if (round == 2 && x != 2) + if (round == _i && x != _i) { ck_assert_int_eq(6, x); } @@ -296,7 +296,7 @@ Suite *linked_list_enumerator_suite_create() tc = tcase_create("insert_before()"); tcase_add_checked_fixture(tc, setup_list, teardown_list); - tcase_add_test(tc, test_insert_before); + tcase_add_loop_test(tc, test_insert_before, 1, 5); tcase_add_test(tc, test_insert_before_ends); tcase_add_test(tc, test_insert_before_empty); suite_add_tcase(s, tc); From cca70ed331bb0cdb6be0d9c63f6a4238fa35639f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 13:22:07 +0100 Subject: [PATCH 19/48] Add additional tests for linked_list_t --- .../tests/test_linked_list_enumerator.c | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c index 724aba09e..1342aec8a 100644 --- a/src/libstrongswan/tests/test_linked_list_enumerator.c +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -79,6 +79,21 @@ START_TEST(test_reset_enumerator) } END_TEST +START_TEST(test_has_more_empty) +{ + enumerator_t *enumerator; + intptr_t x; + + list->destroy(list); + list = linked_list_create(); + enumerator = list->create_enumerator(list); + ck_assert(!list->has_more(list, enumerator)); + ck_assert(!enumerator->enumerate(enumerator, &x)); + ck_assert(!list->has_more(list, enumerator)); + enumerator->destroy(enumerator); +} +END_TEST + START_TEST(test_has_more) { enumerator_t *enumerator; @@ -280,6 +295,36 @@ START_TEST(test_remove_at_ends) } END_TEST +/******************************************************************************* + * create list from enumerator + */ + +START_TEST(test_create_from_enumerator) +{ + enumerator_t *enumerator, *enumerator_other; + linked_list_t *other; + intptr_t x, y; + int count = 0; + + enumerator = list->create_enumerator(list); + other = linked_list_create_from_enumerator(enumerator); + ck_assert_int_eq(other->get_count(list), 5); + + enumerator = list->create_enumerator(list); + enumerator_other = other->create_enumerator(other); + while (enumerator->enumerate(enumerator, &x) && + enumerator_other->enumerate(enumerator_other, &y)) + { + ck_assert_int_eq(x, y); + count++; + } + ck_assert_int_eq(count, 5); + enumerator_other->destroy(enumerator_other); + enumerator->destroy(enumerator); + other->destroy(other); +} +END_TEST + Suite *linked_list_enumerator_suite_create() { Suite *s; @@ -291,6 +336,7 @@ Suite *linked_list_enumerator_suite_create() tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_enumerate); tcase_add_test(tc, test_reset_enumerator); + tcase_add_test(tc, test_has_more_empty); tcase_add_test(tc, test_has_more); suite_add_tcase(s, tc); @@ -308,5 +354,10 @@ Suite *linked_list_enumerator_suite_create() tcase_add_test(tc, test_remove_at_ends); suite_add_tcase(s, tc); + tc = tcase_create("create_from_enumerator"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_create_from_enumerator); + suite_add_tcase(s, tc); + return s; } From afb6d9c3015feeb6814d534e45fbc0b5afa879bf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 13:27:19 +0100 Subject: [PATCH 20/48] Improve tests for linked_list_t.replace() --- .../tests/test_linked_list_enumerator.c | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c index 1342aec8a..d44f7ab9f 100644 --- a/src/libstrongswan/tests/test_linked_list_enumerator.c +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -219,7 +219,7 @@ END_TEST START_TEST(test_replace) { enumerator_t *enumerator; - intptr_t x; + intptr_t x, y; int round; round = 1; @@ -227,7 +227,8 @@ START_TEST(test_replace) while (enumerator->enumerate(enumerator, &x)) { ck_assert_int_eq(round, x); - list->replace(list, enumerator, (void*)(uintptr_t)(6 - round)); + y = (intptr_t)list->replace(list, enumerator, (void*)(intptr_t)(6 - round)); + ck_assert_int_eq(round, y); round++; } list->reset_enumerator(list, enumerator); @@ -241,6 +242,20 @@ START_TEST(test_replace) } END_TEST +START_TEST(test_replace_first) +{ + enumerator_t *enumerator; + intptr_t x; + + enumerator = list->create_enumerator(list); + x = (intptr_t)list->replace(list, enumerator, (void*)6); + ck_assert_int_eq(x, 0); + ck_assert(enumerator->enumerate(enumerator, &x)); + ck_assert_int_eq(x, 1); + enumerator->destroy(enumerator); +} +END_TEST + START_TEST(test_remove_at) { enumerator_t *enumerator; @@ -350,6 +365,7 @@ Suite *linked_list_enumerator_suite_create() tc = tcase_create("modify"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_replace); + tcase_add_test(tc, test_replace_first); tcase_add_test(tc, test_remove_at); tcase_add_test(tc, test_remove_at_ends); suite_add_tcase(s, tc); From c721d6b6a3ebcb43bb7b562d25b28d6f8acadc3b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 14:10:12 +0100 Subject: [PATCH 21/48] Add test cases for invoke_* and clone_* of linked_list_t --- src/libstrongswan/tests/test_linked_list.c | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/libstrongswan/tests/test_linked_list.c b/src/libstrongswan/tests/test_linked_list.c index d2f6147e2..32b5cd7c9 100644 --- a/src/libstrongswan/tests/test_linked_list.c +++ b/src/libstrongswan/tests/test_linked_list.c @@ -254,6 +254,138 @@ START_TEST(test_find_callback) } END_TEST +/******************************************************************************* + * invoke + */ + +typedef struct invoke_t invoke_t; + +struct invoke_t { + int val; + void (*invoke)(invoke_t *item, void *a, void *b, void *c, void *d, int *sum); +}; + +static void invoke(intptr_t item, void *a, void *b, void *c, void *d, int *sum) +{ + ck_assert(a == (void*)1); + ck_assert(b == (void*)2); + ck_assert(c == (void*)3); + ck_assert(d == (void*)4); + *sum += item; +} + +static void invoke_offset(invoke_t *item, void *a, void *b, void *c, void *d, int *sum) +{ + invoke(item->val, a, b, c, d, sum); +} + +START_TEST(test_invoke_function) +{ + int sum = 0; + + list->insert_last(list, (void*)1); + list->insert_last(list, (void*)2); + list->insert_last(list, (void*)3); + list->insert_last(list, (void*)4); + list->insert_last(list, (void*)5); + list->invoke_function(list, (linked_list_invoke_t)invoke, 1, 2, 3, 4, &sum); + ck_assert_int_eq(sum, 15); +} +END_TEST + +START_TEST(test_invoke_offset) +{ + invoke_t items[] = { + { .val = 1, .invoke = invoke_offset, }, + { .val = 2, .invoke = invoke_offset, }, + { .val = 3, .invoke = invoke_offset, }, + { .val = 4, .invoke = invoke_offset, }, + { .val = 5, .invoke = invoke_offset, }, + }; + int i, sum = 0; + + for (i = 0; i < countof(items); i++) + { + list->insert_last(list, &items[i]); + } + list->invoke_offset(list, offsetof(invoke_t, invoke), 1, 2, 3, 4, &sum); + ck_assert_int_eq(sum, 15); +} +END_TEST + +/******************************************************************************* + * clone + */ + +typedef struct clone_t clone_t; + +struct clone_t { + void *val; + void *(*clone)(clone_t *item); +}; + +static void *clone(void *item) +{ + return item; +} + +static void *clone_offset(clone_t *item) +{ + return clone(item->val); +} + +static void test_clone(linked_list_t *list) +{ + intptr_t x; + int round = 1; + + ck_assert_int_eq(list->get_count(list), 5); + while (list->remove_first(list, (void*)&x) == SUCCESS) + { + ck_assert_int_eq(round, x); + round++; + } + ck_assert_int_eq(round, 6); +} + +START_TEST(test_clone_function) +{ + linked_list_t *other; + + list->insert_last(list, (void*)1); + list->insert_last(list, (void*)2); + list->insert_last(list, (void*)3); + list->insert_last(list, (void*)4); + list->insert_last(list, (void*)5); + + other = list->clone_function(list, clone); + test_clone(other); + other->destroy(other); +} +END_TEST + +START_TEST(test_clone_offset) +{ + linked_list_t *other; + clone_t items[] = { + { .val = (void*)1, .clone = clone_offset, }, + { .val = (void*)2, .clone = clone_offset, }, + { .val = (void*)3, .clone = clone_offset, }, + { .val = (void*)4, .clone = clone_offset, }, + { .val = (void*)5, .clone = clone_offset, }, + }; + int i; + + for (i = 0; i < countof(items); i++) + { + list->insert_last(list, &items[i]); + } + other = list->clone_offset(list, offsetof(clone_t, clone)); + test_clone(other); + other->destroy(other); +} +END_TEST + Suite *linked_list_suite_create() { Suite *s; @@ -281,5 +413,17 @@ Suite *linked_list_suite_create() tcase_add_test(tc, test_find_callback); suite_add_tcase(s, tc); + tc = tcase_create("invoke"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_invoke_function); + tcase_add_test(tc, test_invoke_offset); + suite_add_tcase(s, tc); + + tc = tcase_create("clone"); + tcase_add_checked_fixture(tc, setup_list, teardown_list); + tcase_add_test(tc, test_clone_function); + tcase_add_test(tc, test_clone_offset); + suite_add_tcase(s, tc); + return s; } From 0713c90927223afbe0bc40c36a60ec51bd4aed70 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 14:45:07 +0100 Subject: [PATCH 22/48] Test remove and remove_at of hashtable_t if all items are in the same bucket --- src/libstrongswan/tests/test_hashtable.c | 59 ++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/libstrongswan/tests/test_hashtable.c b/src/libstrongswan/tests/test_hashtable.c index 802016f59..bee773535 100644 --- a/src/libstrongswan/tests/test_hashtable.c +++ b/src/libstrongswan/tests/test_hashtable.c @@ -137,9 +137,8 @@ END_TEST * remove */ -START_TEST(test_remove) +static void do_remove(char *k1, char *k2, char *k3) { - char *k1 = "key1", *k2 = "key2", *k3 = "key3"; char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; ht->put(ht, k1, v1); @@ -164,6 +163,26 @@ START_TEST(test_remove) ck_assert(ht->get(ht, k2) == NULL); ck_assert(ht->get(ht, k3) == NULL); } + +START_TEST(test_remove) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3"; + + do_remove(k1, k2, k3); +} +END_TEST + +START_TEST(test_remove_one_bucket) +{ + char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c"; + + ht->destroy(ht); + /* set a capacity to avoid rehashing, which would change the items' order */ + ht = hashtable_create((hashtable_hash_t)hash_match, + (hashtable_equals_t)equals, 8); + + do_remove(k1, k2, k3); +} END_TEST /******************************************************************************* @@ -195,6 +214,15 @@ START_TEST(test_enumerator) enumerator->destroy(enumerator); ck_assert_int_eq(count, 3); + count = 0; + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, NULL, NULL)) + { + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 3); + value = ht->remove(ht, k1); value = ht->remove(ht, k2); value = ht->remove(ht, k3); @@ -214,10 +242,9 @@ END_TEST * remove_at */ -START_TEST(test_remove_at) +static void do_remove_at(char *k1, char *k2, char *k3) { - char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key; - char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value; + char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value, *key; enumerator_t *enumerator; ht->put(ht, k1, v1); @@ -225,6 +252,7 @@ START_TEST(test_remove_at) ht->put(ht, k3, v3); enumerator = ht->create_enumerator(ht); + ht->remove_at(ht, enumerator); while (enumerator->enumerate(enumerator, &key, &value)) { if (streq(key, k2)) @@ -258,6 +286,25 @@ START_TEST(test_remove_at) ck_assert(ht->get(ht, k2) == NULL); ck_assert(ht->get(ht, k3) == NULL); } + +START_TEST(test_remove_at) +{ + char *k1 = "key1", *k2 = "key2", *k3 = "key3"; + + do_remove_at(k1, k2, k3); +} +END_TEST + +START_TEST(test_remove_at_one_bucket) +{ + char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c"; + + ht->destroy(ht); + /* set a capacity to avoid rehashing, which would change the items' order */ + ht = hashtable_create((hashtable_hash_t)hash_match, + (hashtable_equals_t)equals, 8); + do_remove_at(k1, k2, k3); +} END_TEST Suite *hashtable_suite_create() @@ -279,6 +326,7 @@ Suite *hashtable_suite_create() tc = tcase_create("remove"); tcase_add_checked_fixture(tc, setup_ht, teardown_ht); tcase_add_test(tc, test_remove); + tcase_add_test(tc, test_remove_one_bucket); suite_add_tcase(s, tc); tc = tcase_create("enumerator"); @@ -289,6 +337,7 @@ Suite *hashtable_suite_create() tc = tcase_create("remove_at"); tcase_add_checked_fixture(tc, setup_ht, teardown_ht); tcase_add_test(tc, test_remove_at); + tcase_add_test(tc, test_remove_at_one_bucket); suite_add_tcase(s, tc); return s; From 7e9f6b276b8133d26a0704741d98a00dd3cc4ec2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 15:35:19 +0100 Subject: [PATCH 23/48] Additional and improved enumerator_t tests --- src/libstrongswan/tests/test_enumerator.c | 223 +++++++++++++++++++++- 1 file changed, 219 insertions(+), 4 deletions(-) diff --git a/src/libstrongswan/tests/test_enumerator.c b/src/libstrongswan/tests/test_enumerator.c index f49ae3380..687e476c1 100644 --- a/src/libstrongswan/tests/test_enumerator.c +++ b/src/libstrongswan/tests/test_enumerator.c @@ -77,12 +77,25 @@ START_TEST(test_token) END_TEST /******************************************************************************* - * utility for filtered and nested tests + * utilities for filtered, nested and cleaner tests */ +static int destroy_data_called; + +static void setup_destroy_data() +{ + destroy_data_called = 0; +} + +static void teardown_destroy_data() +{ + ck_assert_int_eq(destroy_data_called, 1); +} + static void destroy_data(void *data) { fail_if(data != (void*)101, "data does not match '101' in destructor"); + destroy_data_called++; } /******************************************************************************* @@ -103,6 +116,13 @@ static bool filter(void *data, int *v, int *vo, int *w, int *wo, return TRUE; } +static bool filter_odd(void *data, int *item, int *out) +{ + fail_if(data != (void*)101, "data does not match '101' in filter function"); + *out = *item; + return *item % 2 == 0; +} + START_TEST(test_filtered) { int round, v, w, x, y, z; @@ -125,6 +145,33 @@ START_TEST(test_filtered) round++; } enumerator->destroy(enumerator); + ck_assert_int_eq(round, 6); + + list->destroy(list); +} +END_TEST + +START_TEST(test_filtered_filter) +{ + int count, x; + linked_list_t *list; + enumerator_t *enumerator; + + list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4, + (void*)5, NULL); + + count = 0; + /* should also work without destructor, so set this manually */ + destroy_data_called = 1; + enumerator = enumerator_create_filter(list->create_enumerator(list), + (void*)filter_odd, (void*)101, NULL); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert(x % 2 == 0); + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 2); list->destroy(list); } @@ -140,12 +187,19 @@ static enumerator_t* create_inner(linked_list_t *outer, void *data) return outer->create_enumerator(outer); } +static enumerator_t* create_inner_null(void *outer, void *data) +{ + ck_assert(outer == (void*)1); + fail_if(data != (void*)101, "data does not match '101' in nested constr."); + return NULL; +} + START_TEST(test_nested) { - intptr_t x; - int round; linked_list_t *list, *l1, *l2, *l3; enumerator_t *enumerator; + intptr_t x; + int round; l1 = linked_list_create_with_items((void*)1, (void*)2, NULL); l2 = linked_list_create(); @@ -154,13 +208,14 @@ START_TEST(test_nested) round = 1; enumerator = enumerator_create_nested(list->create_enumerator(list), - (void*)create_inner, (void*)101, destroy_data); + (void*)create_inner, (void*)101, destroy_data); while (enumerator->enumerate(enumerator, &x)) { ck_assert_int_eq(round, x); round++; } enumerator->destroy(enumerator); + ck_assert_int_eq(round, 6); list->destroy(list); l1->destroy(l1); @@ -169,6 +224,150 @@ START_TEST(test_nested) } END_TEST +START_TEST(test_nested_reset) +{ + linked_list_t *list, *l1, *l2, *l3; + enumerator_t *outer, *enumerator; + intptr_t x; + int count = 0; + + l1 = linked_list_create_with_items((void*)1, (void*)2, NULL); + l2 = linked_list_create(); + l3 = linked_list_create_with_items((void*)3, (void*)4, (void*)5, NULL); + list = linked_list_create_with_items(l1, l2, l3, NULL); + + outer = list->create_enumerator(list); + enumerator = enumerator_create_nested(outer, (void*)create_inner, + (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &x)) + { + count++; + } + ck_assert_int_eq(count, 5); + + list->reset_enumerator(list, outer); + ck_assert(enumerator->enumerate(enumerator, &x)); + ck_assert_int_eq(x, 1); + enumerator->destroy(enumerator); + + list->destroy(list); + l1->destroy(l1); + l2->destroy(l2); + l3->destroy(l3); +} +END_TEST + +START_TEST(test_nested_empty) +{ + linked_list_t *list; + enumerator_t *enumerator; + intptr_t x; + int count; + + list = linked_list_create(); + count = 0; + enumerator = enumerator_create_nested(list->create_enumerator(list), + (void*)create_inner, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &x)) + { + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 0); + + list->destroy(list); +} +END_TEST + +START_TEST(test_nested_null) +{ + linked_list_t *list; + enumerator_t *enumerator; + intptr_t x; + int count; + + list = linked_list_create_with_items((void*)1, NULL); + + count = 0; + /* should also work without destructor, so set this manually */ + destroy_data_called = 1; + enumerator = enumerator_create_nested(list->create_enumerator(list), + (void*)create_inner_null, (void*)101, NULL); + while (enumerator->enumerate(enumerator, &x)) + { + count++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(count, 0); + + list->destroy(list); +} +END_TEST + +/******************************************************************************* + * cleaner test + */ + +START_TEST(test_cleaner) +{ + enumerator_t *enumerator; + linked_list_t *list; + intptr_t x; + int round; + + list = linked_list_create_with_items((void*)1, (void*)2, NULL); + + round = 1; + enumerator = enumerator_create_cleaner(list->create_enumerator(list), + destroy_data, (void*)101); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(round, x); + round++; + } + ck_assert_int_eq(round, 3); + enumerator->destroy(enumerator); + list->destroy(list); +} +END_TEST + +/******************************************************************************* + * single test + */ + +static void single_cleanup(void *data) +{ + ck_assert_int_eq((intptr_t)data, 1); +} + +static void do_test_single(enumerator_t *enumerator) +{ + intptr_t x; + + ck_assert(enumerator->enumerate(enumerator, &x)); + ck_assert_int_eq(x, 1); + ck_assert(!enumerator->enumerate(enumerator, &x)); + enumerator->destroy(enumerator); +} + +START_TEST(test_single) +{ + enumerator_t *enumerator; + + enumerator = enumerator_create_single((void*)1, NULL); + do_test_single(enumerator); +} +END_TEST + +START_TEST(test_single_cleanup) +{ + enumerator_t *enumerator; + + enumerator = enumerator_create_single((void*)1, single_cleanup); + do_test_single(enumerator); +} +END_TEST + Suite *enumerator_suite_create() { Suite *s; @@ -181,11 +380,27 @@ Suite *enumerator_suite_create() suite_add_tcase(s, tc); tc = tcase_create("filtered"); + tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data); tcase_add_test(tc, test_filtered); + tcase_add_test(tc, test_filtered_filter); suite_add_tcase(s, tc); tc = tcase_create("nested"); + tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data); tcase_add_test(tc, test_nested); + tcase_add_test(tc, test_nested_reset); + tcase_add_test(tc, test_nested_empty); + tcase_add_test(tc, test_nested_null); + suite_add_tcase(s, tc); + + tc = tcase_create("cleaner"); + tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data); + tcase_add_test(tc, test_cleaner); + suite_add_tcase(s, tc); + + tc = tcase_create("single"); + tcase_add_test(tc, test_single); + tcase_add_test(tc, test_single_cleanup); suite_add_tcase(s, tc); return s; From 0e55270aeabc41a78240a691707103c6f9cde56b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 16:15:10 +0100 Subject: [PATCH 24/48] Remove dead code in token enumerator Since we always search for the nearest separator (and strip them from the front of the next token) there can't be any separators left at the end of a token. --- src/libstrongswan/collections/enumerator.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/libstrongswan/collections/enumerator.c b/src/libstrongswan/collections/enumerator.c index f80cdabd2..8049ac016 100644 --- a/src/libstrongswan/collections/enumerator.c +++ b/src/libstrongswan/collections/enumerator.c @@ -264,7 +264,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token) } } - /* trim trailing characters/separators */ + /* trim trailing characters */ pos--; while (pos >= *token) { @@ -278,17 +278,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token) } trim++; } - sep = this->sep; - while (*sep) - { - if (*sep == *pos) - { - *(pos--) = '\0'; - break; - } - sep++; - } - if (!*trim && !*sep) + if (!*trim) { break; } From 9a8c873e90c9f5a38eee9a8df840d6ac679d564b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 16:35:28 +0100 Subject: [PATCH 25/48] Add tests for lib->get|set --- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + src/libstrongswan/tests/test_utils.c | 58 +++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_utils.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index b0eb0a546..e99b3b5e9 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -6,7 +6,7 @@ test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ test_chunk.c test_hashtable.c test_identification.c \ - test_threading.c + test_threading.c test_utils.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 7dc40ff2e..d830efded 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -39,6 +39,7 @@ int main() srunner_add_suite(sr, hashtable_suite_create()); srunner_add_suite(sr, identification_suite_create()); srunner_add_suite(sr, threading_suite_create()); + srunner_add_suite(sr, utils_suite_create()); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 8ec40a721..a5529fe1d 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -25,5 +25,6 @@ Suite *linked_list_enumerator_suite_create(); Suite *hashtable_suite_create(); Suite *identification_suite_create(); Suite *threading_suite_create(); +Suite *utils_suite_create(); #endif /** TEST_RUNNER_H_ */ diff --git a/src/libstrongswan/tests/test_utils.c b/src/libstrongswan/tests/test_utils.c new file mode 100644 index 000000000..451f5b9ff --- /dev/null +++ b/src/libstrongswan/tests/test_utils.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + + +#include + +#include + +/******************************************************************************* + * object storage on lib + */ + +START_TEST(test_objects) +{ + char *k1 = "key1", *k2 = "key2"; + char *v1 = "val1", *val; + + ck_assert(lib->get(lib, k1) == NULL); + + ck_assert(lib->set(lib, k1, v1)); + ck_assert(!lib->set(lib, k1, v1)); + + val = lib->get(lib, k1); + ck_assert(val != NULL); + ck_assert(streq(val, v1)); + + ck_assert(lib->set(lib, k1, NULL)); + ck_assert(!lib->set(lib, k2, NULL)); + + ck_assert(lib->get(lib, k1) == NULL); +} +END_TEST + +Suite *utils_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("utils"); + + tc = tcase_create("objects"); + tcase_add_test(tc, test_objects); + suite_add_tcase(s, tc); + + return s; +} From ab73ae67d3eed94ed16b41fdc66afee5e7027222 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 17:41:04 +0100 Subject: [PATCH 26/48] Also capture coverage data for tests but filter them from the result Otherwise calls from test cases to static inline functions are not captured. --- Makefile.am | 20 ++++++++++++-------- src/libstrongswan/tests/Makefile.am | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Makefile.am b/Makefile.am index c7ece4a21..d9bae5f20 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,20 +37,24 @@ Doxyfile : Doxyfile.in apidoc : Doxyfile doxygen -if COVERAGE -cov-reset: +cov-reset-common: @rm -rf $(top_builddir)/coverage @find $(top_builddir) -name "*.gcda" -delete + +if COVERAGE +cov-reset: cov-reset-common @lcov --zerocounters --directory $(top_builddir) cov-report: @mkdir $(top_builddir)/coverage lcov -c -o $(top_builddir)/coverage/coverage.info -d $(top_builddir) + lcov -r $(top_builddir)/coverage/coverage.info '*/tests/*' \ + -o $(top_builddir)/coverage/coverage.cleaned.info genhtml --num-spaces 4 --legend \ -t "$(PACKAGE_STRING)" \ -o $(top_builddir)/coverage/html \ -p `readlink -m $(abs_top_srcdir)`/src \ - $(top_builddir)/coverage/coverage.info + $(top_builddir)/coverage/coverage.cleaned.info @echo "Coverage Report at $(top_builddir)/coverage/html" >&2 coverage: @@ -58,12 +62,12 @@ coverage: @$(MAKE) check @$(MAKE) cov-report else -cov-reset: - coverage: @echo "reconfigure with --enable-coverage" endif -clean-local: - @$(MAKE) cov-reset - rm -rf apidoc +clean-local: cov-reset-common + @find $(top_builddir) -name "*.gcno" -delete + @rm -rf apidoc + +.PHONY: cov-reset-common cov-reset cov-report coverage \ No newline at end of file diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index e99b3b5e9..5e3a2526d 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -8,9 +8,9 @@ test_runner_SOURCES = \ test_chunk.c test_hashtable.c test_identification.c \ test_threading.c test_utils.c - test_runner_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ + @COVERAGE_CFLAGS@ \ @CHECK_CFLAGS@ test_runner_LDFLAGS = @COVERAGE_LDFLAGS@ From c2dba63bd4025ce1a2d1c49a86aee624acf19eb1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 Mar 2013 19:56:14 +0100 Subject: [PATCH 27/48] Additional tests for chunk_t --- src/libstrongswan/tests/test_chunk.c | 627 ++++++++++++++++++++++++++- 1 file changed, 625 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/tests/test_chunk.c b/src/libstrongswan/tests/test_chunk.c index 6ea80b977..9c5115b13 100644 --- a/src/libstrongswan/tests/test_chunk.c +++ b/src/libstrongswan/tests/test_chunk.c @@ -19,13 +19,391 @@ #include +/******************************************************************************* + * utilities + */ + +static void assert_chunk_empty(chunk_t chunk) +{ + ck_assert(chunk.len == 0 && chunk.ptr == NULL); +} + +/******************************************************************************* + * equals + */ + +START_TEST(test_chunk_equals) +{ + chunk_t chunk = chunk_from_str("chunk"); + chunk_t chunk_a, chunk_b; + + chunk_a = chunk_empty; + chunk_b = chunk_empty; + ck_assert(!chunk_equals(chunk_a, chunk_b)); + + chunk_a = chunk; + ck_assert(!chunk_equals(chunk_a, chunk_b)); + chunk_b = chunk; + ck_assert(chunk_equals(chunk_a, chunk_b)); + + chunk_b = chunk_from_str("asdf"); + ck_assert(!chunk_equals(chunk_a, chunk_b)); + + chunk_b = chunk_from_str("chunk"); + ck_assert(chunk_equals(chunk_a, chunk_b)); +} +END_TEST + +/******************************************************************************* + * chunk_compare test + */ + +static struct { + int result; + chunk_t a; + chunk_t b; +} compare_data[] = { + { 0, { NULL, 0 }, { NULL, 0 }}, + { 0, chunk_from_chars(0x00), chunk_from_chars(0x00)}, + {-1, chunk_from_chars(0x00), chunk_from_chars(0x01)}, + { 1, chunk_from_chars(0x01), chunk_from_chars(0x00)}, + { 0, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x00)}, + {-1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x01)}, + { 1, chunk_from_chars(0x00, 0x01), chunk_from_chars(0x00, 0x00)}, + {-1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x01, 0x00)}, + { 1, chunk_from_chars(0x01, 0x00), chunk_from_chars(0x00, 0x00)}, + {-1, chunk_from_chars(0xff), chunk_from_chars(0x00, 0x00)}, + { 1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0xff)}, +}; + +START_TEST(test_compare) +{ + int result, expected; + + result = chunk_compare(compare_data[_i].a, compare_data[_i].b); + expected = compare_data[_i].result; + ck_assert((result == 0 && expected == 0) || + (result < 0 && expected < 0) || + (result > 0 && expected > 0)); +} +END_TEST + +/******************************************************************************* + * clear + */ + +START_TEST(test_chunk_clear) +{ + chunk_t chunk; + u_char *ptr; + int i; + + chunk = chunk_empty; + chunk_clear(&chunk); + chunk_free(&chunk); + + chunk = chunk_alloc(64); + ptr = chunk.ptr; + for (i = 0; i < 64; i++) + { + chunk.ptr[i] = i; + } + chunk_clear(&chunk); + assert_chunk_empty(chunk); + /* check memory area of freed chunk */ + for (i = 0; i < 64; i++) + { + ck_assert(ptr[i] == 0 || ptr[i] != i); + } +} +END_TEST + +/******************************************************************************* + * chunk_length + */ + +START_TEST(test_chunk_length) +{ + chunk_t a, b, c; + size_t len; + + a = chunk_empty; + b = chunk_empty; + c = chunk_empty; + len = chunk_length("ccc", a, b, c); + ck_assert_int_eq(len, 0); + + a = chunk_from_str("foo"); + b = chunk_from_str("bar"); + len = chunk_length("ccc", a, b, c); + ck_assert_int_eq(len, 6); + + len = chunk_length("zcc", a, b, c); + ck_assert_int_eq(len, 0); + + len = chunk_length("czc", a, b, c); + ck_assert_int_eq(len, 3); + + a = chunk_from_str("foo"); + b = chunk_from_str("bar"); + c = chunk_from_str("baz"); + len = chunk_length("ccc", a, b, c); + ck_assert_int_eq(len, 9); +} +END_TEST + +/******************************************************************************* + * chunk_create_cat + */ + +START_TEST(test_chunk_create_cat) +{ + chunk_t foo, bar; + chunk_t a, b, c; + u_char *ptra, *ptrb; + + foo = chunk_from_str("foo"); + bar = chunk_from_str("bar"); + + /* to simplify things we use the chunk_cata macro */ + + a = chunk_empty; + b = chunk_empty; + c = chunk_cata("cc", a, b); + ck_assert_int_eq(c.len, 0); + ck_assert(c.ptr != NULL); + + a = foo; + b = bar; + c = chunk_cata("cc", a, b); + ck_assert_int_eq(c.len, 6); + ck_assert(chunk_equals(c, chunk_from_str("foobar"))); + + a = chunk_clone(foo); + b = chunk_clone(bar); + c = chunk_cata("mm", a, b); + ck_assert_int_eq(c.len, 6); + ck_assert(chunk_equals(c, chunk_from_str("foobar"))); + + a = chunk_clone(foo); + b = chunk_clone(bar); + ptra = a.ptr; + ptrb = b.ptr; + c = chunk_cata("ss", a, b); + ck_assert_int_eq(c.len, 6); + ck_assert(chunk_equals(c, chunk_from_str("foobar"))); + /* check memory area of cleared chunk */ + ck_assert(!chunk_equals(foo, chunk_create(ptra, 3))); + ck_assert(!chunk_equals(bar, chunk_create(ptrb, 3))); +} +END_TEST + +/******************************************************************************* + * chunk_split + */ + +static bool mem_in_chunk(u_char *ptr, chunk_t chunk) +{ + return ptr >= chunk.ptr && ptr < (chunk.ptr + chunk.len); +} + +START_TEST(test_chunk_split) +{ + chunk_t foo, bar, foobar; + chunk_t a, b, c; + u_char *ptra, *ptrb; + + foo = chunk_from_str("foo"); + bar = chunk_from_str("bar"); + foobar = chunk_from_str("foobar"); + + chunk_split(foobar, "aa", 3, &a, 3, &b); + ck_assert(chunk_equals(a, foo)); + ck_assert(chunk_equals(b, bar)); + ck_assert(!mem_in_chunk(a.ptr, foobar)); + ck_assert(!mem_in_chunk(b.ptr, foobar)); + chunk_free(&a); + chunk_free(&b); + + chunk_split(foobar, "mm", 3, &a, 3, &b); + ck_assert(chunk_equals(a, foo)); + ck_assert(chunk_equals(b, bar)); + ck_assert(mem_in_chunk(a.ptr, foobar)); + ck_assert(mem_in_chunk(b.ptr, foobar)); + + chunk_split(foobar, "am", 3, &a, 3, &b); + ck_assert(chunk_equals(a, foo)); + ck_assert(chunk_equals(b, bar)); + ck_assert(!mem_in_chunk(a.ptr, foobar)); + ck_assert(mem_in_chunk(b.ptr, foobar)); + chunk_free(&a); + + a = chunk_alloca(3); + ptra = a.ptr; + b = chunk_alloca(3); + ptrb = b.ptr; + chunk_split(foobar, "cc", 3, &a, 3, &b); + ck_assert(chunk_equals(a, foo)); + ck_assert(chunk_equals(b, bar)); + ck_assert(a.ptr == ptra); + ck_assert(b.ptr == ptrb); + + chunk_split(foobar, "mm", 1, NULL, 2, &a, 2, NULL, 1, &b); + ck_assert(chunk_equals(a, chunk_from_str("oo"))); + ck_assert(chunk_equals(b, chunk_from_str("r"))); + + chunk_split(foobar, "mm", 6, &a, 6, &b); + ck_assert(chunk_equals(a, foobar)); + assert_chunk_empty(b); + + chunk_split(foobar, "mac", 12, &a, 12, &b, 12, &c); + ck_assert(chunk_equals(a, foobar)); + assert_chunk_empty(b); + assert_chunk_empty(c); +} +END_TEST + +/******************************************************************************* + * chunk_skip[_zero] + */ + +START_TEST(test_chunk_skip) +{ + chunk_t foobar, a; + + foobar = chunk_from_str("foobar"); + a = foobar; + a = chunk_skip(a, 0); + ck_assert(chunk_equals(a, foobar)); + a = chunk_skip(a, 1); + ck_assert(chunk_equals(a, chunk_from_str("oobar"))); + a = chunk_skip(a, 2); + ck_assert(chunk_equals(a, chunk_from_str("bar"))); + a = chunk_skip(a, 3); + assert_chunk_empty(a); + + a = foobar; + a = chunk_skip(a, 6); + assert_chunk_empty(a); + + a = foobar; + a = chunk_skip(a, 10); + assert_chunk_empty(a); +} +END_TEST + +START_TEST(test_chunk_skip_zero) +{ + chunk_t foobar, a; + + a = chunk_empty; + a = chunk_skip_zero(a); + assert_chunk_empty(a); + + foobar = chunk_from_str("foobar"); + a = foobar; + a = chunk_skip_zero(a); + ck_assert(chunk_equals(a, foobar)); + + a = chunk_from_chars(0x00, 0xaa, 0xbb, 0xcc); + a = chunk_skip_zero(a); + ck_assert(chunk_equals(a, chunk_from_chars(0xaa, 0xbb, 0xcc))); + a = chunk_skip_zero(a); + ck_assert(chunk_equals(a, chunk_from_chars(0xaa, 0xbb, 0xcc))); +} +END_TEST + +/******************************************************************************* + * BASE16 encoding test + */ + +START_TEST(test_base16) +{ + /* test vectors from RFC 4648: + * + * BASE16("") = "" + * BASE16("f") = "66" + * BASE16("fo") = "666F" + * BASE16("foo") = "666F6F" + * BASE16("foob") = "666F6F62" + * BASE16("fooba") = "666F6F6261" + * BASE16("foobar") = "666F6F626172" + */ + typedef struct { + bool upper; + char *in; + char *out; + } testdata_t; + + testdata_t test[] = { + {TRUE, "", ""}, + {TRUE, "f", "66"}, + {TRUE, "fo", "666F"}, + {TRUE, "foo", "666F6F"}, + {TRUE, "foob", "666F6F62"}, + {TRUE, "fooba", "666F6F6261"}, + {TRUE, "foobar", "666F6F626172"}, + {FALSE, "", ""}, + {FALSE, "f", "66"}, + {FALSE, "fo", "666f"}, + {FALSE, "foo", "666f6f"}, + {FALSE, "foob", "666f6f62"}, + {FALSE, "fooba", "666f6f6261"}, + {FALSE, "foobar", "666f6f626172"}, + }; + testdata_t test_colon[] = { + {TRUE, "", ""}, + {TRUE, "f", "66"}, + {TRUE, "fo", "66:6F"}, + {TRUE, "foo", "66:6F:6F"}, + {FALSE, "foob", "66:6f:6f:62"}, + {FALSE, "fooba", "66:6f:6f:62:61"}, + {FALSE, "foobar", "66:6f:6f:62:61:72"}, + {FALSE, "foobar", "66:6f6f:6261:72"}, + }; + int i; + + for (i = 0; i < countof(test); i++) + { + chunk_t out; + + out = chunk_to_hex(chunk_create(test[i].in, strlen(test[i].in)), NULL, + test[i].upper); + ck_assert_str_eq(out.ptr, test[i].out); + free(out.ptr); + } + + for (i = 0; i < countof(test); i++) + { + chunk_t out; + + out = chunk_from_hex(chunk_create(test[i].out, strlen(test[i].out)), NULL); + fail_unless(strneq(out.ptr, test[i].in, out.len), + "base16 conversion error - should '%s', is %#B", + test[i].in, &out); + free(out.ptr); + } + + for (i = 0; i < countof(test_colon); i++) + { + chunk_t out; + + out = chunk_from_hex(chunk_create(test_colon[i].out, strlen(test_colon[i].out)), NULL); + fail_unless(strneq(out.ptr, test_colon[i].in, out.len), + "base16 conversion error - should '%s', is %#B", + test_colon[i].in, &out); + free(out.ptr); + } +} +END_TEST + /******************************************************************************* * BASE64 encoding test */ START_TEST(test_base64) { - /* test vectors from RFC4648: + /* test vectors from RFC 4648: * * BASE64("") = "" * BASE64("f") = "Zg==" @@ -73,6 +451,137 @@ START_TEST(test_base64) } END_TEST +/******************************************************************************* + * BASE32 encoding test + */ + +START_TEST(test_base32) +{ + /* test vectors from RFC 4648: + * + * BASE32("") = "" + * BASE32("f") = "MY======" + * BASE32("fo") = "MZXQ====" + * BASE32("foo") = "MZXW6===" + * BASE32("foob") = "MZXW6YQ=" + * BASE32("fooba") = "MZXW6YTB" + * BASE32("foobar") = "MZXW6YTBOI======" + */ + typedef struct { + char *in; + char *out; + } testdata_t; + + testdata_t test[] = { + {"", ""}, + {"f", "MY======"}, + {"fo", "MZXQ===="}, + {"foo", "MZXW6==="}, + {"foob", "MZXW6YQ="}, + {"fooba", "MZXW6YTB"}, + {"foobar", "MZXW6YTBOI======"}, + }; + int i; + + for (i = 0; i < countof(test); i++) + { + chunk_t out; + + out = chunk_to_base32(chunk_create(test[i].in, strlen(test[i].in)), NULL); + ck_assert_str_eq(out.ptr, test[i].out); + free(out.ptr); + } +} +END_TEST + +/******************************************************************************* + * chunk_increment test + */ + +static struct { + bool overflow; + chunk_t in; + chunk_t out; +} increment_data[] = { + {TRUE, { NULL, 0 }, { NULL, 0 }}, + {FALSE, chunk_from_chars(0x00), chunk_from_chars(0x01)}, + {FALSE, chunk_from_chars(0xfe), chunk_from_chars(0xff)}, + {TRUE, chunk_from_chars(0xff), chunk_from_chars(0x00)}, + {FALSE, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x01)}, + {FALSE, chunk_from_chars(0x00, 0xff), chunk_from_chars(0x01, 0x00)}, + {FALSE, chunk_from_chars(0xfe, 0xff), chunk_from_chars(0xff, 0x00)}, + {TRUE, chunk_from_chars(0xff, 0xff), chunk_from_chars(0x00, 0x00)}, +}; + +START_TEST(test_increment) +{ + chunk_t chunk; + bool overflow; + + chunk = chunk_clonea(increment_data[_i].in); + overflow = chunk_increment(chunk); + ck_assert(overflow == increment_data[_i].overflow); + ck_assert(!increment_data[_i].out.ptr || + chunk_equals(chunk, increment_data[_i].out)); +} +END_TEST + +/******************************************************************************* + * chunk_printable tests + */ + +static struct { + bool printable; + chunk_t in; + char *out; +} printable_data[] = { + {TRUE, chunk_from_chars(0x31), "1"}, + {FALSE, chunk_from_chars(0x00), "?"}, + {FALSE, chunk_from_chars(0x31, 0x00), "1?"}, + {FALSE, chunk_from_chars(0x00, 0x31), "?1"}, + {TRUE, chunk_from_chars(0x3f, 0x31), "?1"}, + {FALSE, chunk_from_chars(0x00, 0x31, 0x00), "?1?"}, + {FALSE, chunk_from_chars(0x00, 0x31, 0x00, 0x32), "?1?2"}, +}; + +START_TEST(test_printable) +{ + bool printable; + + printable = chunk_printable(printable_data[_i].in, NULL, ' '); + ck_assert(printable == printable_data[_i].printable); +} +END_TEST + +START_TEST(test_printable_sanitize) +{ + chunk_t sane, expected; + bool printable; + + printable = chunk_printable(printable_data[_i].in, &sane, '?'); + ck_assert(printable == printable_data[_i].printable); + expected = chunk_from_str(printable_data[_i].out); + ck_assert(chunk_equals(sane, expected)); + chunk_free(&sane); +} +END_TEST + +START_TEST(test_printable_empty) +{ + chunk_t sane; + bool printable; + + printable = chunk_printable(chunk_empty, NULL, ' '); + ck_assert(printable); + + sane.ptr = (void*)1; + sane.len = 1; + printable = chunk_printable(chunk_empty, &sane, ' '); + ck_assert(printable); + assert_chunk_empty(sane); +} +END_TEST + /******************************************************************************* * test for chunk_mac(), i.e. SipHash-2-4 */ @@ -182,6 +691,70 @@ START_TEST(test_chunk_mac) } END_TEST + +/******************************************************************************* + * test for chunk_hash[_inc]() + */ + +START_TEST(test_chunk_hash) +{ + chunk_t chunk; + u_int32_t hash_a, hash_b, hash_c; + + chunk = chunk_from_str("asdf"); + + /* output is randomized, so there are no test-vectors we could use */ + hash_a = chunk_hash(chunk); + hash_b = chunk_hash(chunk); + ck_assert(hash_a == hash_b); + hash_b = chunk_hash_inc(chunk, hash_a); + ck_assert(hash_a != hash_b); + hash_c = chunk_hash_inc(chunk, hash_a); + ck_assert(hash_b == hash_c); +} +END_TEST + +/******************************************************************************* + * printf_hook tests + */ + +static struct { + chunk_t in; + char *out; +} printf_hook_data[] = { + {chunk_from_chars(), ""}, + {chunk_from_chars(0x00), "00"}, + {chunk_from_chars(0x00, 0x01), "00:01"}, + {chunk_from_chars(0x00, 0x01, 0x02), "00:01:02"}, +}; + +START_TEST(test_printf_hook_hash) +{ + char buf[16]; + int len; + + len = snprintf(buf, sizeof(buf), "%#B", &printf_hook_data[_i].in); + ck_assert(len >= 0 && len < sizeof(buf)); + ck_assert_str_eq(buf, printf_hook_data[_i].out); +} +END_TEST + +START_TEST(test_printf_hook) +{ + char buf[128], mem[128]; + int len; + + /* %B should be the same as %b, which is what we check, comparing the + * acutal result could be tricky as %b prints the chunk's memory address */ + len = snprintf(buf, sizeof(buf), "%B", &printf_hook_data[_i].in); + ck_assert(len >= 0 && len < sizeof(buf)); + len = snprintf(mem, sizeof(mem), "%b", printf_hook_data[_i].in.ptr, + (u_int)printf_hook_data[_i].in.len); + ck_assert(len >= 0 && len < sizeof(mem)); + ck_assert_str_eq(buf, mem); +} +END_TEST + Suite *chunk_suite_create() { Suite *s; @@ -189,13 +762,63 @@ Suite *chunk_suite_create() s = suite_create("chunk"); - tc = tcase_create("base64"); + tc = tcase_create("equals"); + tcase_add_test(tc, test_chunk_equals); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_compare"); + tcase_add_loop_test(tc, test_compare, 0, countof(compare_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("clear"); + tcase_add_test(tc, test_chunk_clear); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_length"); + tcase_add_test(tc, test_chunk_length); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_create_cat"); + tcase_add_test(tc, test_chunk_create_cat); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_split"); + tcase_add_test(tc, test_chunk_split); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_skip"); + tcase_add_test(tc, test_chunk_skip); + tcase_add_test(tc, test_chunk_skip_zero); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_increment"); + tcase_add_loop_test(tc, test_increment, 0, countof(increment_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("chunk_printable"); + tcase_add_loop_test(tc, test_printable, 0, countof(printable_data)); + tcase_add_loop_test(tc, test_printable_sanitize, 0, countof(printable_data)); + tcase_add_test(tc, test_printable_empty); + suite_add_tcase(s, tc); + + tc = tcase_create("baseXX"); tcase_add_test(tc, test_base64); + tcase_add_test(tc, test_base32); + tcase_add_test(tc, test_base16); suite_add_tcase(s, tc); tc = tcase_create("chunk_mac"); tcase_add_test(tc, test_chunk_mac); suite_add_tcase(s, tc); + tc = tcase_create("chunk_hash"); + tcase_add_test(tc, test_chunk_hash); + suite_add_tcase(s, tc); + + tc = tcase_create("printf_hook"); + tcase_add_loop_test(tc, test_printf_hook_hash, 0, countof(printf_hook_data)); + tcase_add_loop_test(tc, test_printf_hook, 0, countof(printf_hook_data)); + suite_add_tcase(s, tc); + return s; } From 819c02dbc6e9203cb1f1df8ef76c7a5a5d8c205d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 10:25:11 +0100 Subject: [PATCH 28/48] timeval_add_ms() fixed 1000000us are exactly 1s so. --- src/libstrongswan/utils/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 46eaf7b64..8637c3c82 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -507,7 +507,7 @@ time_t time_monotonic(timeval_t *tv); static inline void timeval_add_ms(timeval_t *tv, u_int ms) { tv->tv_usec += ms * 1000; - while (tv->tv_usec > 1000000 /* 1s */) + while (tv->tv_usec >= 1000000 /* 1s */) { tv->tv_usec -= 1000000; tv->tv_sec++; From 438a6693ca54a782342f27f30faa667a4e6612cc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 11:03:26 +0100 Subject: [PATCH 29/48] Removed unused clalloc() function --- src/libstrongswan/utils/utils.c | 13 ------------- src/libstrongswan/utils/utils.h | 5 ----- 2 files changed, 18 deletions(-) diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 2f38d8a93..ba32720ea 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -45,19 +45,6 @@ ENUM(status_names, SUCCESS, NEED_MORE, "NEED_MORE", ); -/** - * Described in header. - */ -void *clalloc(void * pointer, size_t size) -{ - void *data; - data = malloc(size); - - memcpy(data, pointer, size); - - return (data); -} - /** * Described in header. */ diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 8637c3c82..ff1a007c1 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -375,11 +375,6 @@ typedef struct timespec timespec_t; */ typedef struct sockaddr sockaddr_t; -/** - * Clone a data to a newly allocated buffer - */ -void *clalloc(void *pointer, size_t size); - /** * Same as memcpy, but XORs src into dst instead of copy */ From 7b91011d6edf2febbce28f3d73d149a7f0b81843 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 14:12:53 +0100 Subject: [PATCH 30/48] Allow memstr() to be called with NULL arguments --- src/libstrongswan/utils/utils.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index ba32720ea..aa59f4a4d 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -102,7 +102,12 @@ void memwipe_noinline(void *ptr, size_t n) void *memstr(const void *haystack, const char *needle, size_t n) { unsigned const char *pos = haystack; - size_t l = strlen(needle); + size_t l; + + if (!haystack || !needle || (l = strlen(needle)) == 0) + { + return NULL; + } for (; n >= l; ++pos, --n) { if (memeq(pos, needle, l)) From af67613ed6b67788db6ba15e0fb1975a5d394d7b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 10:58:09 +0100 Subject: [PATCH 31/48] Added tests for utils/utils.[ch] --- src/libstrongswan/tests/test_utils.c | 375 +++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) diff --git a/src/libstrongswan/tests/test_utils.c b/src/libstrongswan/tests/test_utils.c index 451f5b9ff..9efc77621 100644 --- a/src/libstrongswan/tests/test_utils.c +++ b/src/libstrongswan/tests/test_utils.c @@ -17,6 +17,7 @@ #include #include +#include /******************************************************************************* * object storage on lib @@ -43,6 +44,349 @@ START_TEST(test_objects) } END_TEST +/******************************************************************************* + * test return_... functions + */ + +START_TEST(test_return_functions) +{ + ck_assert(return_null() == NULL); + ck_assert(return_null("asdf", 5, NULL, 1, "qwer") == NULL); + + ck_assert(return_true() == TRUE); + ck_assert(return_true("asdf", 5, NULL, 1, "qwer") == TRUE); + + ck_assert(return_false() == FALSE); + ck_assert(return_false("asdf", 5, NULL, 1, "qwer") == FALSE); + + ck_assert(return_failed() == FAILED); + ck_assert(return_failed("asdf", 5, NULL, 1, "qwer") == FAILED); + + ck_assert(return_success() == SUCCESS); + ck_assert(return_success("asdf", 5, NULL, 1, "qwer") == SUCCESS); + + /* just make sure this works */ + nop(); + nop("asdf", 5, NULL, 1, "qwer"); +} +END_TEST + +/******************************************************************************* + * timeval_add_ms + */ + +START_TEST(test_timeval_add_ms) +{ + timeval_t tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + timeval_add_ms(&tv, 0); + ck_assert_int_eq(tv.tv_sec, 0); + ck_assert_int_eq(tv.tv_usec, 0); + + timeval_add_ms(&tv, 1); + ck_assert_int_eq(tv.tv_sec, 0); + ck_assert_int_eq(tv.tv_usec, 1000); + + timeval_add_ms(&tv, 0); + ck_assert_int_eq(tv.tv_sec, 0); + ck_assert_int_eq(tv.tv_usec, 1000); + + timeval_add_ms(&tv, 999); + ck_assert_int_eq(tv.tv_sec, 1); + ck_assert_int_eq(tv.tv_usec, 0); + + timeval_add_ms(&tv, 0); + ck_assert_int_eq(tv.tv_sec, 1); + ck_assert_int_eq(tv.tv_usec, 0); + + timeval_add_ms(&tv, 1000); + ck_assert_int_eq(tv.tv_sec, 2); + ck_assert_int_eq(tv.tv_usec, 0); + + timeval_add_ms(&tv, 1500); + ck_assert_int_eq(tv.tv_sec, 3); + ck_assert_int_eq(tv.tv_usec, 500000); +} +END_TEST + +/******************************************************************************* + * htoun/untoh + */ + +START_TEST(test_htoun) +{ + chunk_t net64, expected; + u_int16_t host16 = 513; + u_int32_t net16 = 0, host32 = 67305985; + u_int64_t net32 = 0, host64 = 578437695752307201; + + net64 = chunk_alloca(16); + memset(net64.ptr, 0, net64.len); + + expected = chunk_from_chars(0x00, 0x02, 0x01, 0x00); + htoun16((char*)&net16 + 1, host16); + ck_assert(chunk_equals(expected, chunk_from_thing(net16))); + + expected = chunk_from_chars(0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00); + htoun32((u_int16_t*)&net32 + 1, host32); + ck_assert(chunk_equals(expected, chunk_from_thing(net32))); + + expected = chunk_from_chars(0x00, 0x00, 0x00, 0x00, + 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, + 0x00, 0x00, 0x00, 0x00); + htoun64((u_int32_t*)net64.ptr + 1, host64); + ck_assert(chunk_equals(expected, net64)); +} +END_TEST + +START_TEST(test_untoh) +{ + chunk_t net; + u_int16_t host16; + u_int32_t host32; + u_int64_t host64; + + net = chunk_from_chars(0x00, 0x02, 0x01, 0x00); + host16 = untoh16(net.ptr + 1); + ck_assert(host16 == 513); + + net = chunk_from_chars(0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00); + host32 = untoh32(net.ptr + 2); + ck_assert(host32 == 67305985); + + net = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00); + host64 = untoh64(net.ptr + 4); + ck_assert(host64 == 578437695752307201); +} +END_TEST + +/******************************************************************************* + * memxor + */ + +static void do_memxor(chunk_t a, chunk_t b, chunk_t exp) +{ + chunk_t dst; + + dst = chunk_clonea(a); + dst.len = b.len; + memxor(dst.ptr, b.ptr, b.len); + ck_assert(chunk_equals(dst, exp)); +} + +START_TEST(test_memxor) +{ + chunk_t a, b, dst; + int i; + + a = chunk_alloca(64); + memset(a.ptr, 0, a.len); + b = chunk_alloca(64); + for (i = 0; i < 64; i++) + { + b.ptr[i] = i; + b.len = i; + do_memxor(a, b, b); + } + b.len = 64; + do_memxor(a, b, b); + + dst = chunk_clonea(a); + memxor(dst.ptr, b.ptr, b.len); + ck_assert(chunk_equals(dst, b)); + + memxor(dst.ptr, b.ptr, 0); + memxor(dst.ptr, b.ptr, 1); + memxor(dst.ptr + 1, b.ptr + 1, 1); + memxor(dst.ptr + 2, b.ptr + 2, b.len - 2); + ck_assert(chunk_equals(dst, a)); +} +END_TEST + +START_TEST(test_memxor_aligned) +{ + u_int64_t a = 0, b = 0; + chunk_t ca, cb; + int i; + + ca = chunk_from_thing(a); + cb = chunk_from_thing(b); + + for (i = 0; i < 8; i++) + { + cb.ptr[i] = i + 1; + } + + /* 64-bit aligned */ + memxor(ca.ptr, cb.ptr, 8); + ck_assert(a == b); + /* 32-bit aligned source */ + a = 0; + memxor(ca.ptr, cb.ptr + 4, 4); + ck_assert(chunk_equals(ca, chunk_from_chars(0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x00))); + /* 16-bit aligned source */ + a = 0; + memxor(ca.ptr, cb.ptr + 2, 6); + ck_assert(chunk_equals(ca, chunk_from_chars(0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x00, 0x00))); + /* 8-bit aligned source */ + a = 0; + memxor(ca.ptr, cb.ptr + 1, 7); + ck_assert(chunk_equals(ca, chunk_from_chars(0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x00))); +} +END_TEST + +/******************************************************************************* + * memstr + */ + +static struct { + char *haystack; + char *needle; + size_t n; + int offset; +} memstr_data[] = { + {NULL, NULL, 0, -1}, + {NULL, NULL, 3, -1}, + {NULL, "abc", 0, -1}, + {NULL, "abc", 3, -1}, + {"", "", 0, -1}, + {"abc", NULL, 3, -1}, + {"abc", "", 3, -1}, + {"abc", "abc", 3, 0}, + {" abc", "abc", 4, 1}, + {" abc", "abc", 3, -1}, + {"abcabc", "abc", 6, 0}, + {" abc ", "abc", 5, 1}, +}; + +START_TEST(test_memstr) +{ + char *ret; + + ret = memstr(memstr_data[_i].haystack, memstr_data[_i].needle, memstr_data[_i].n); + if (memstr_data[_i].offset >= 0) + { + ck_assert(ret == memstr_data[_i].haystack + memstr_data[_i].offset); + } + else + { + ck_assert(ret == NULL); + } +} +END_TEST + +/******************************************************************************* + * translate + */ + +static struct { + char *in; + char *from; + char *to; + char *out; +} translate_data[] = { + {NULL, "", "", NULL}, + {"abc", "", "", "abc"}, + {"abc", "", "x", "abc"}, + {"abc", "x", "", "abc"}, + {"abc", "abc", "xyz", "xyz"}, + {"aabbcc", "abc", "xyz", "xxyyzz"}, + {"abbaccb", "abc", "xyz", "xyyxzzy"}, + {"abxyzc", "abc", "xyz", "xyxyzz"}, + {"abcdef", "abc", "xyz", "xyzdef"}, + {"aaa", "abc", "xyz", "xxx"}, + {"abc", "aaa", "xyz", "xbc"}, + {"abc", "abc", "xxx", "xxx"}, +}; + +START_TEST(test_translate) +{ + char *str, *ret; + + str = strdupnull(translate_data[_i].in); + ret = translate(str, translate_data[_i].from, translate_data[_i].to); + ck_assert(ret == str); + if (ret != translate_data[_i].out) + { + ck_assert_str_eq(str, translate_data[_i].out); + } + free(str); +} +END_TEST + +/******************************************************************************* + * time_printf_hook + */ + +static struct { + time_t in; + bool utc; + char *out; +} time_data[] = { + {UNDEFINED_TIME, FALSE, "--- -- --:--:-- ----"}, + {UNDEFINED_TIME, TRUE , "--- -- --:--:-- UTC ----"}, + {1, FALSE, "Jan 01 01:00:01 1970"}, + {1, TRUE , "Jan 01 00:00:01 UTC 1970"}, + {1341150196, FALSE, "Jul 01 15:43:16 2012"}, + {1341150196, TRUE , "Jul 01 13:43:16 UTC 2012"}, +}; + +START_TEST(test_time_printf_hook) +{ + char buf[32]; + int len; + + len = snprintf(buf, sizeof(buf), "%T", &time_data[_i].in, time_data[_i].utc); + ck_assert(len >= 0 && len < sizeof(buf)); + ck_assert_str_eq(buf, time_data[_i].out); +} +END_TEST + +/******************************************************************************* + * time_delta_printf_hook + */ + +static struct { + time_t a; + time_t b; + char *out; +} time_delta_data[] = { + {0, 0, "0 seconds"}, + {0, 1, "1 second"}, + {0, -1, "1 second"}, + {1, 0, "1 second"}, + {0, 2, "2 seconds"}, + {2, 0, "2 seconds"}, + {0, 60, "60 seconds"}, + {0, 120, "120 seconds"}, + {0, 121, "2 minutes"}, + {0, 3600, "60 minutes"}, + {0, 7200, "120 minutes"}, + {0, 7201, "2 hours"}, + {0, 86400, "24 hours"}, + {0, 172800, "48 hours"}, + {0, 172801, "2 days"}, + {172801, 86400, "24 hours"}, +}; + +START_TEST(test_time_delta_printf_hook) +{ + char buf[16]; + int len; + + len = snprintf(buf, sizeof(buf), "%V", &time_delta_data[_i].a, &time_delta_data[_i].b); + ck_assert(len >= 0 && len < sizeof(buf)); + ck_assert_str_eq(buf, time_delta_data[_i].out); +} +END_TEST + Suite *utils_suite_create() { Suite *s; @@ -54,5 +398,36 @@ Suite *utils_suite_create() tcase_add_test(tc, test_objects); suite_add_tcase(s, tc); + tc = tcase_create("return functions"); + tcase_add_test(tc, test_return_functions); + suite_add_tcase(s, tc); + + tc = tcase_create("timeval_add_ms"); + tcase_add_test(tc, test_timeval_add_ms); + suite_add_tcase(s, tc); + + tc = tcase_create("htoun,untoh"); + tcase_add_test(tc, test_htoun); + tcase_add_test(tc, test_untoh); + suite_add_tcase(s, tc); + + tc = tcase_create("memxor"); + tcase_add_test(tc, test_memxor); + tcase_add_test(tc, test_memxor_aligned); + suite_add_tcase(s, tc); + + tc = tcase_create("memstr"); + tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("translate"); + tcase_add_loop_test(tc, test_translate, 0, countof(translate_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("printf_hooks"); + tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data)); + tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data)); + suite_add_tcase(s, tc); + return s; } From 456a31e8957e5928c62a8e83460b10602335e99d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 16:30:29 +0100 Subject: [PATCH 32/48] Parse empty string as ID_ANY --- src/libstrongswan/utils/identification.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 4176320dc..348da627c 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -921,8 +921,9 @@ identification_t *identification_create_from_string(char *string) } else if (strchr(string, '@') == NULL) { - if (streq(string, "%any") - || streq(string, "%any6") + if (streq(string, "") + || streq(string, "%any") + || streq(string, "%any6") || streq(string, "0.0.0.0") || streq(string, "*") || streq(string, "::") From c1be5d66cd68fbe7491532497f14a08992024c39 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 16:33:39 +0100 Subject: [PATCH 33/48] Use local variable in chunk_from_str() This allows using strdup() or other string functions as argument without calling them twice. --- src/libstrongswan/utils/chunk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index cfda6ee77..b9f2bf266 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -191,9 +191,9 @@ static inline void chunk_clear(chunk_t *chunk) #define chunk_from_thing(thing) chunk_create((char*)&(thing), sizeof(thing)) /** - * Initialize a chunk from a static string, not containing 0-terminator + * Initialize a chunk from a string, not containing 0-terminator */ -#define chunk_from_str(str) chunk_create(str, strlen(str)) +#define chunk_from_str(str) ({char *x = (str); chunk_create(x, strlen(x));}) /** * Allocate a chunk on the heap From 78c37de15a06de470cc82e428e268ebf9f1f9d9f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 16:50:36 +0100 Subject: [PATCH 34/48] Use chunk_from_str in identification_from_string We always have a non-empty string in those cases as "" is now handled as ID_ANY. --- src/libstrongswan/utils/identification.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 348da627c..ca0e5c93e 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -915,7 +915,7 @@ identification_t *identification_create_from_string(char *string) else { this = identification_create(ID_KEY_ID); - this->encoded = chunk_clone(chunk_create(string, strlen(string))); + this->encoded = chunk_from_str(strdup(string)); } return &this->public; } @@ -948,11 +948,7 @@ identification_t *identification_create_from_string(char *string) else { /* not IPv4, mostly FQDN */ this = identification_create(ID_FQDN); - this->encoded.len = strlen(string); - if (this->encoded.len) - { - this->encoded.ptr = strdup(string); - } + this->encoded = chunk_from_str(strdup(string)); } return &this->public; } @@ -969,11 +965,7 @@ identification_t *identification_create_from_string(char *string) else { /* not IPv4/6 fallback to KEY_ID */ this = identification_create(ID_KEY_ID); - this->encoded.len = strlen(string); - if (this->encoded.len) - { - this->encoded.ptr = strdup(string); - } + this->encoded = chunk_from_str(strdup(string)); } return &this->public; } @@ -997,7 +989,7 @@ identification_t *identification_create_from_string(char *string) string += 1; this->encoded.len = strlen(string); if (this->encoded.len) - { + { /* if we only got an @ */ this->encoded.ptr = strdup(string); } return &this->public; @@ -1006,11 +998,7 @@ identification_t *identification_create_from_string(char *string) else { this = identification_create(ID_RFC822_ADDR); - this->encoded.len = strlen(string); - if (this->encoded.len) - { - this->encoded.ptr = strdup(string); - } + this->encoded = chunk_from_str(strdup(string)); return &this->public; } } From c04498b60838d399dd3c3751119b1ab5a7118442 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 23 Apr 2013 12:06:54 +0200 Subject: [PATCH 35/48] Fix output of ASN.1 GN --- src/libstrongswan/utils/identification.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index ca0e5c93e..326ccf25a 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -799,7 +799,7 @@ int identification_printf_hook(printf_hook_data_t *data, dntoa(this->encoded, buf, sizeof(buf)); break; case ID_DER_ASN1_GN: - snprintf(buf, sizeof(buf), "(ASN.1 general Name"); + snprintf(buf, sizeof(buf), "(ASN.1 general name)"); break; case ID_KEY_ID: if (chunk_printable(this->encoded, NULL, '?') && From 10584df24f4fa059323aeedc2c29705453622202 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 3 Jun 2013 15:53:46 +0200 Subject: [PATCH 36/48] Fix DN parsing if last RDN has an empty value --- src/libstrongswan/utils/identification.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 326ccf25a..0cb7cb070 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -418,7 +418,7 @@ static status_t atodn(char *src, chunk_t *dn) { break; } - else if (*src != ',' && *src != '/') + else if (*src != ',' && *src != '/' && *src != '\0') { name.ptr = src; name.len = 1; From f00c3506887b124e95e3775d0f74ec9045b22d78 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 3 Jun 2013 16:41:45 +0200 Subject: [PATCH 37/48] Fix DN printing if last RDN has an empty value --- src/libstrongswan/utils/identification.c | 43 ++++++++++++++++++------ 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 0cb7cb070..f94a1c8bb 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -276,6 +276,23 @@ METHOD(identification_t, create_part_enumerator, enumerator_t*, } } +/** + * Print a separator between two RDNs + */ +static inline bool print_separator(char **buf, size_t *len) +{ + int written; + + written = snprintf(*buf, *len, ", "); + if (written < 0 || written >= *len) + { + return FALSE; + } + *buf += written; + *len -= written; + return TRUE; +} + /** * Print a DN with all its RDN in a buffer to present it to the user */ @@ -292,8 +309,14 @@ static void dntoa(chunk_t dn, char *buf, size_t len) { empty = FALSE; - oid = asn1_known_oid(oid_data); + /* previous RDN was empty but it wasn't the last one */ + if (finished && !print_separator(&buf, &len)) + { + break; + } + finished = FALSE; + oid = asn1_known_oid(oid_data); if (oid == OID_UNKNOWN) { written = snprintf(buf, len, "%#B=", &oid_data); @@ -319,21 +342,19 @@ static void dntoa(chunk_t dn, char *buf, size_t len) buf += written; len -= written; - if (data.ptr + data.len != dn.ptr + dn.len) - { - written = snprintf(buf, len, ", "); - if (written < 0 || written >= len) - { - break; - } - buf += written; - len -= written; + if (!data.ptr) + { /* we can't calculate if we're finished, assume we are */ + finished = TRUE; } - else + else if (data.ptr + data.len == dn.ptr + dn.len) { finished = TRUE; break; } + else if (!print_separator(&buf, &len)) + { + break; + } } if (empty) { From b1abf22bd04934714bf7f5a544ce65c0bd2118e5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 3 Jun 2013 17:30:40 +0200 Subject: [PATCH 38/48] Fail DN parsing if OID is unterminated This is the case if the last OID is not followed by a = or if the string starts with a =. --- src/libstrongswan/utils/identification.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index f94a1c8bb..06ec533ea 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -398,7 +398,7 @@ static status_t atodn(char *src, chunk_t *dn) switch (state) { case SEARCH_OID: - if (*src != ' ' && *src != '/' && *src != ',') + if (*src != ' ' && *src != '/' && *src != ',' && *src != '\0') { oid.ptr = src; oid.len = 1; @@ -502,6 +502,11 @@ static status_t atodn(char *src, chunk_t *dn) } } while (*src++ != '\0'); + if (state == READ_OID) + { /* unterminated OID */ + status = INVALID_ARG; + } + /* build the distinguished name sequence */ { int i; @@ -514,7 +519,6 @@ static status_t atodn(char *src, chunk_t *dn) free(rdns[i].ptr); } } - if (status != SUCCESS) { free(dn->ptr); From 06f6d8024577477c2c3dd68653025002dedc6eb1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 28 Mar 2013 16:53:07 +0100 Subject: [PATCH 39/48] Additional tests for identification_t added --- src/libstrongswan/tests/test_identification.c | 530 +++++++++++++++++- 1 file changed, 517 insertions(+), 13 deletions(-) diff --git a/src/libstrongswan/tests/test_identification.c b/src/libstrongswan/tests/test_identification.c index fd6177f34..d21d4c7fa 100644 --- a/src/libstrongswan/tests/test_identification.c +++ b/src/libstrongswan/tests/test_identification.c @@ -18,6 +18,337 @@ #include +/******************************************************************************* + * create (_from_encoding, _from_data, _from_string, _from_sockaddr) + */ + +START_TEST(test_from_encoding) +{ + identification_t *a; + chunk_t expected, encoding; + + /* only ID_ANY is handled differently, for all other types the following + * applies. should we perhaps test that this is in fact the case? */ + expected = chunk_from_str("moon@strongswan.org"); + a = identification_create_from_encoding(ID_RFC822_ADDR, expected); + ck_assert(ID_RFC822_ADDR == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(expected.ptr != encoding.ptr); + ck_assert(chunk_equals(expected, encoding)); + a->destroy(a); + + a = identification_create_from_encoding(ID_ANY, expected); + ck_assert(ID_ANY == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(encoding.ptr == NULL); + ck_assert(encoding.len == 0); + a->destroy(a); +} +END_TEST + +START_TEST(test_from_data) +{ + identification_t *a; + chunk_t expected, encoding; + + /* this uses the DN parser (C=CH) */ + expected = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48); + a = identification_create_from_data(expected); + ck_assert(ID_DER_ASN1_DN == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(expected.ptr != encoding.ptr); + ck_assert(chunk_equals(expected, encoding)); + a->destroy(a); + + /* everything else is handled by the string parser */ + expected = chunk_from_str("moon@strongswan.org"); + a = identification_create_from_data(expected); + ck_assert(ID_RFC822_ADDR == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(expected.ptr != encoding.ptr); + ck_assert(chunk_equals(expected, encoding)); + a->destroy(a); +} +END_TEST + +START_TEST(test_from_sockaddr) +{ + identification_t *a; + chunk_t expected, encoding; + struct sockaddr_in in = { + .sin_family = AF_INET, + }; + struct sockaddr_in6 in6 = { + .sin6_family = AF_INET6, + }; + + expected = chunk_from_chars(0xc0, 0xa8, 0x01, 0x01); + memcpy(&in.sin_addr, expected.ptr, sizeof(in.sin_addr)); + a = identification_create_from_sockaddr((sockaddr_t*)&in); + ck_assert(ID_IPV4_ADDR == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(chunk_equals(expected, encoding)); + a->destroy(a); + + expected = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); + memcpy(&in6.sin6_addr, expected.ptr, sizeof(in6.sin6_addr)); + a = identification_create_from_sockaddr((sockaddr_t*)&in6); + ck_assert(ID_IPV6_ADDR == a->get_type(a)); + encoding = a->get_encoding(a); + ck_assert(chunk_equals(expected, encoding)); + a->destroy(a); + + in6.sin6_family = AF_UNSPEC; + a = identification_create_from_sockaddr((sockaddr_t*)&in6); + ck_assert(ID_ANY == a->get_type(a)); + a->destroy(a); +} +END_TEST + +static struct { + char *id; + id_type_t type; + struct { + enum { + ENC_CHUNK, + ENC_STRING, + ENC_SIMPLE, + } type; + union { + chunk_t c; + char *s; + } data; + } result; +} string_data[] = { + {NULL, ID_ANY, { .type = ENC_CHUNK }}, + {"", ID_ANY, { .type = ENC_CHUNK }}, + {"%any", ID_ANY, { .type = ENC_CHUNK }}, + {"%any6", ID_ANY, { .type = ENC_CHUNK }}, + {"0.0.0.0", ID_ANY, { .type = ENC_CHUNK }}, + {"0::0", ID_ANY, { .type = ENC_CHUNK }}, + {"::", ID_ANY, { .type = ENC_CHUNK }}, + {"*", ID_ANY, { .type = ENC_CHUNK }}, + {"any", ID_FQDN, { .type = ENC_SIMPLE }}, + {"any6", ID_FQDN, { .type = ENC_SIMPLE }}, + {"0", ID_FQDN, { .type = ENC_SIMPLE }}, + {"**", ID_FQDN, { .type = ENC_SIMPLE }}, + {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0xc0, 0xa8, 0x01, 0x01) }}, + {"192.168.",ID_FQDN, { .type = ENC_SIMPLE }}, + {".", ID_FQDN, { .type = ENC_SIMPLE }}, + {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01) }}, + {"fec0::", ID_IPV6_ADDR, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) }}, + {"fec0:", ID_KEY_ID, { .type = ENC_SIMPLE }}, + {":", ID_KEY_ID, { .type = ENC_SIMPLE }}, + {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }}, + {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }}, + {"alice@", ID_RFC822_ADDR, { .type = ENC_SIMPLE }}, + {"alice", ID_FQDN, { .type = ENC_SIMPLE }}, + {"@", ID_FQDN, { .type = ENC_CHUNK }}, + {" @", ID_RFC822_ADDR, { .type = ENC_SIMPLE }}, + {"@strongswan.org", ID_FQDN, { .type = ENC_STRING, + .data.s = "strongswan.org" }}, + {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0xde, 0xad, 0xbe, 0xef) }}, + {"@#deadbee", ID_KEY_ID, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0x0d, 0xea, 0xdb, 0xee) }}, + {"foo=bar", ID_KEY_ID, { .type = ENC_SIMPLE }}, + {"foo=", ID_KEY_ID, { .type = ENC_SIMPLE }}, + {"=bar", ID_KEY_ID, { .type = ENC_SIMPLE }}, + {"C=", ID_DER_ASN1_DN, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0x30, 0x0b, 0x31, 0x09, 0x30, 0x07, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x00)}}, + {"C=CH", ID_DER_ASN1_DN, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}}, + {"C=CH,", ID_DER_ASN1_DN, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}}, + {"C=CH, ", ID_DER_ASN1_DN, { .type = ENC_CHUNK, + .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}}, + {"C=CH, O", ID_KEY_ID, { .type = ENC_SIMPLE }}, +}; + +START_TEST(test_from_string) +{ + identification_t *a; + chunk_t encoding, expected; + char *id; + + id = string_data[_i].id; + a = identification_create_from_string(id); + fail_unless(a->get_type(a) == string_data[_i].type, + "type of id '%s' is %N, %N expected", id, + id_type_names, a->get_type(a), + id_type_names, string_data[_i].type); + + encoding = a->get_encoding(a); + switch (string_data[_i].result.type) + { + case ENC_SIMPLE: + expected = chunk_from_str(string_data[_i].id); + break; + case ENC_STRING: + expected = chunk_from_str(string_data[_i].result.data.s); + break; + case ENC_CHUNK: + expected = string_data[_i].result.data.c; + break; + default: + fail("unexpected result type"); + } + + ck_assert(!id || (char*)encoding.ptr != id); + if (expected.ptr) + { + fail_unless(chunk_equals(encoding, expected), + "parsing '%s' failed\nencoding %B\nexpected %B\n", + id, &encoding, &expected); + } + else + { + ck_assert(encoding.ptr == NULL); + ck_assert(encoding.len == 0); + } + a->destroy(a); +} +END_TEST + +/******************************************************************************* + * printf_hook + */ + +static void string_equals(char *a_str, char *b_str) +{ + identification_t *b; + char buf[128]; + + b = b_str ? identification_create_from_string(b_str) : NULL; + snprintf(buf, sizeof(buf), "%Y", b); + DESTROY_IF(b); + ck_assert_str_eq(a_str, buf); +} + +static void string_equals_id(char *a_str, identification_t *b) +{ + char buf[128]; + + snprintf(buf, sizeof(buf), "%Y", b); + DESTROY_IF(b); + ck_assert_str_eq(a_str, buf); +} + +START_TEST(test_printf_hook) +{ + string_equals("(null)", NULL); + string_equals("%any", ""); + string_equals("%any", "%any"); + string_equals("%any", "*"); + + string_equals("192.168.1.1", "192.168.1.1"); + string_equals_id("(invalid ID_IPV4_ADDR)", + identification_create_from_encoding(ID_IPV4_ADDR, chunk_empty)); + string_equals("fec0::1", "fec0::1"); + string_equals("fec0::1", "fec0:0:0::1"); + string_equals_id("(invalid ID_IPV6_ADDR)", + identification_create_from_encoding(ID_IPV6_ADDR, chunk_empty)); + + string_equals_id("(unknown ID type: 255)", + identification_create_from_encoding(255, chunk_empty)); + + string_equals("moon@strongswan.org", "moon@strongswan.org"); + string_equals("MOON@STRONGSWAN.ORG", "MOON@STRONGSWAN.ORG"); + /* non-printable characters */ + string_equals_id("????@strongswan.org", identification_create_from_encoding(ID_RFC822_ADDR, + chunk_from_chars(0xfa, 0xfb, 0xfc, 0xfd, 0x40, 0x73, 0x74, 0x72, + 0x6f, 0x6e, 0x67, 0x73, 0x77, 0x61, 0x6e, 0x2e, + 0x6f, 0x72, 0x67))); + + /* not a DN => ID_KEY_ID => no normalization */ + string_equals("C=CH, AsdF=asdf", "C=CH, AsdF=asdf"); + string_equals_id("moon@strongswan.org", identification_create_from_encoding(ID_KEY_ID, + chunk_from_str("moon@strongswan.org"))); + /* non-printable characters */ + string_equals_id("de:ad:be:ef", identification_create_from_encoding(ID_KEY_ID, + chunk_from_chars(0xde, 0xad, 0xbe, 0xef))); + /* printable characters */ + string_equals_id("ABCDEFGHIJKLMNOPQRS", + identification_create_from_encoding(ID_KEY_ID, + chunk_from_chars(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53))); + /* ABCDEFGHIJKLMNOPQRST is printable but has the length of a SHA1 hash */ + string_equals_id("41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54", + identification_create_from_encoding(ID_KEY_ID, + chunk_from_chars(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54))); + + string_equals_id("", identification_create_from_encoding(ID_DER_ASN1_DN, chunk_empty)); + string_equals("C=", "C="); + string_equals("C=", "C=,"); + string_equals("C=", "C=, "); + string_equals("C=", "C= , "); + string_equals("C=, O=strongSwan", "C=, O=strongSwan"); + string_equals("C=CH, O=", "C=CH, O="); + string_equals("C=CH, O=strongSwan, CN=strongswan.org", + "C=CH, O=strongSwan, CN=strongswan.org"); + string_equals("CN=strongswan.org, O=strongSwan, C=CH", + "cn=strongswan.org, o=strongSwan, c=CH"); + string_equals("C=CH, O=strongSwan, CN=strongswan.org", + "C=CH,O=strongSwan,CN=strongswan.org"); + string_equals("C=CH, O=strongSwan, CN=strongswan.org", + "/C=CH/O=strongSwan/CN=strongswan.org"); + string_equals("CN=strongswan.org, O=strongSwan, C=CH", + "CN=strongswan.org,O=strongSwan,C=CH"); + + string_equals("C=CH, E=moon@strongswan.org, CN=moon", + "C=CH, email=moon@strongswan.org, CN=moon"); + string_equals("C=CH, E=moon@strongswan.org, CN=moon", + "C=CH, emailAddress=moon@strongswan.org, CN=moon"); + + /* C=CH, pseudonym=ANO (pseudonym is currently not recognized) */ + string_equals_id("C=CH, 55:04:41=ANO", identification_create_from_encoding(ID_DER_ASN1_DN, + chunk_from_chars(0x30, 0x19, 0x31, 0x17, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x41, 0x13, 0x03, 0x41, 0x4e, 0x4f))); + /* C=CH, O=strongSwan (but instead of a 2nd OID -0x06- we got NULL -0x05) */ + string_equals_id("C=CH, (invalid ID_DER_ASN1_DN)", identification_create_from_encoding(ID_DER_ASN1_DN, + chunk_from_chars(0x30, 0x20, 0x31, 0x1e, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x30, 0x11, 0x05, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x73, 0x74, 0x72, + 0x6f, 0x6e, 0x67, 0x53, 0x77, 0x61, 0x6e))); + /* moon@strongswan.org as GN */ + string_equals_id("(ASN.1 general name)", identification_create_from_encoding(ID_DER_ASN1_GN, + chunk_from_chars(0x81, 0x14, 0x6d, 0x6f, 0x6f, 0x6e, 0x40, 0x73, 0x74, + 0x72, 0x6f, 0x6e, 0x67, 0x73, 0x77, 0x61, 0x6e, 0x2e, + 0x6f, 0x72, 0x67))); +} +END_TEST + +START_TEST(test_printf_hook_width) +{ + identification_t *a; + char buf[128]; + + a = identification_create_from_string("moon@strongswan.org"); + snprintf(buf, sizeof(buf), "%25Y", a); + ck_assert_str_eq(" moon@strongswan.org", buf); + snprintf(buf, sizeof(buf), "%-*Y", 25, a); + ck_assert_str_eq("moon@strongswan.org ", buf); + snprintf(buf, sizeof(buf), "%5Y", a); + ck_assert_str_eq("moon@strongswan.org", buf); + DESTROY_IF(a); +} +END_TEST + /******************************************************************************* * equals */ @@ -29,6 +360,7 @@ static bool id_equals(identification_t *a, char *b_str) b = identification_create_from_string(b_str); equals = a->equals(a, b); + equals = equals && b->equals(b, a); b->destroy(b); return equals; } @@ -39,14 +371,23 @@ START_TEST(test_equals) chunk_t encoding, fuzzed; int i; + /* this test also tests identification_create_from_string with DNs */ a = identification_create_from_string( - "C=CH, E=martin@strongswan.org, CN=martin"); + "C=CH, E=moon@strongswan.org, CN=moon"); - ck_assert(id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); - ck_assert(id_equals(a, "C=ch, E=martin@STRONGSWAN.ORG, CN=Martin")); - ck_assert(!id_equals(a, "C=CN, E=martin@strongswan.org, CN=martin")); - ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin")); - ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin")); + ck_assert(id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon")); + ck_assert(id_equals(a, "C==CH, E==moon@strongswan.org,,, CN==moon")); + ck_assert(id_equals(a, " C=CH, E=moon@strongswan.org, CN=moon ")); + ck_assert(id_equals(a, "C=ch, E=moon@STRONGSWAN.ORG, CN=Moon")); + ck_assert(id_equals(a, "/C=CH/E=moon@strongswan.org/CN=moon")); + ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org/CN=moon")); + ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org,CN=moon")); + ck_assert(id_equals(a, "C=CH / E=moon@strongswan.org , CN=moon")); + + ck_assert(!id_equals(a, "C=CH E=moon@strongswan.org CN=moon")); + ck_assert(!id_equals(a, "C=CN, E=moon@strongswan.org, CN=moon")); + ck_assert(!id_equals(a, "E=moon@strongswan.org, C=CH, CN=moon")); + ck_assert(!id_equals(a, "E=moon@strongswan.org, C=CH, CN=moon")); encoding = chunk_clone(a->get_encoding(a)); a->destroy(a); @@ -54,14 +395,18 @@ START_TEST(test_equals) /* simple fuzzing, increment each byte of encoding */ for (i = 0; i < encoding.len; i++) { - if (i == 11 || i == 30 || i == 62) + if (i == 11 || i == 30 || i == 60) { /* skip ASN.1 type fields, as equals() handles them graceful */ continue; } fuzzed = chunk_clone(encoding); fuzzed.ptr[i]++; a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); - ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); + if (id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon")) + { + printf("%d %B\n%B\n", i, &fuzzed, &encoding); + } + ck_assert(!id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon")); a->destroy(a); free(fuzzed.ptr); } @@ -69,14 +414,14 @@ START_TEST(test_equals) /* and decrement each byte of encoding */ for (i = 0; i < encoding.len; i++) { - if (i == 11 || i == 30 || i == 62) + if (i == 11 || i == 30 || i == 60) { continue; } fuzzed = chunk_clone(encoding); fuzzed.ptr[i]--; a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed); - ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin")); + ck_assert(!id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon")); a->destroy(a); free(fuzzed.ptr); } @@ -84,6 +429,53 @@ START_TEST(test_equals) } END_TEST +START_TEST(test_equals_any) +{ + identification_t *a, *b; + + a = identification_create_from_string("%any"); + b = identification_create_from_encoding(ID_ANY, chunk_empty); + ck_assert(a->equals(a, b)); + ck_assert(b->equals(b, a)); + b->destroy(b); + + b = identification_create_from_string("C=CH, O=strongSwan, CN=strongswan.org"); + ck_assert(!a->equals(a, b)); + ck_assert(!b->equals(b, a)); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_equals_binary) +{ + identification_t *a, *b; + chunk_t encoding; + + encoding = chunk_from_str("foobar="); + /* strings containing = are parsed as KEY_ID if they aren't valid ASN.1 DNs */ + a = identification_create_from_string("foobar="); + ck_assert(a->get_type(a) == ID_KEY_ID); + b = identification_create_from_encoding(ID_KEY_ID, encoding); + ck_assert(a->equals(a, b)); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_equals_fqdn) +{ + identification_t *a; + + a = identification_create_from_string("ipsec.strongswan.org"); + ck_assert(id_equals(a, "IPSEC.strongswan.org")); + ck_assert(id_equals(a, "ipsec.strongSwan.org")); + ck_assert(id_equals(a, "ipsec.strongSwan.ORG")); + ck_assert(!id_equals(a, "strongswan.org")); + a->destroy(a); +} +END_TEST + /******************************************************************************* * matches */ @@ -103,20 +495,88 @@ START_TEST(test_matches) { identification_t *a; - a = identification_create_from_string("C=CH, E=martin@strongswan.org, CN=martin"); + a = identification_create_from_string("C=CH, E=moon@strongswan.org, CN=moon"); - ck_assert(id_matches(a, "C=CH, E=martin@strongswan.org, CN=martin", ID_MATCH_PERFECT)); - ck_assert(id_matches(a, "C=CH, E=*, CN=martin", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "C=CH, E=moon@strongswan.org, CN=moon", ID_MATCH_PERFECT)); + ck_assert(id_matches(a, "C=CH, E=*, CN=moon", ID_MATCH_ONE_WILDCARD)); ck_assert(id_matches(a, "C=CH, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 1)); ck_assert(id_matches(a, "C=*, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 2)); ck_assert(id_matches(a, "C=*, E=*, CN=*, O=BADInc", ID_MATCH_NONE)); ck_assert(id_matches(a, "C=*, E=*", ID_MATCH_NONE)); ck_assert(id_matches(a, "C=*, E=a@b.c, CN=*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "%any", ID_MATCH_ANY)); a->destroy(a); } END_TEST +START_TEST(test_matches_any) +{ + identification_t *a; + + a = identification_create_from_string("%any"); + + ck_assert(id_matches(a, "%any", ID_MATCH_ANY)); + ck_assert(id_matches(a, "", ID_MATCH_ANY)); + ck_assert(id_matches(a, "*", ID_MATCH_ANY)); + ck_assert(id_matches(a, "moon@strongswan.org", ID_MATCH_NONE)); + ck_assert(id_matches(a, "vpn.strongswan.org", ID_MATCH_NONE)); + a->destroy(a); +} +END_TEST + +START_TEST(test_matches_binary) +{ + identification_t *a; + + /* strings containing = are parsed as KEY_ID if they aren't valid ASN.1 DNs */ + a = identification_create_from_string("foo=bar"); + ck_assert(a->get_type(a) == ID_KEY_ID); + ck_assert(id_matches(a, "%any", ID_MATCH_ANY)); + ck_assert(id_matches(a, "foo=bar", ID_MATCH_PERFECT)); + ck_assert(id_matches(a, "bar=foo", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*=bar", ID_MATCH_NONE)); + ck_assert(id_matches(a, "foo=*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE)); + a->destroy(a); +} +END_TEST + +START_TEST(test_matches_string) +{ + identification_t *a; + + a = identification_create_from_string("moon@strongswan.org"); + + ck_assert(id_matches(a, "moon@strongswan.org", ID_MATCH_PERFECT)); + ck_assert(id_matches(a, "*@strongswan.org", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "*@*.org", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*@*", ID_MATCH_NONE)); + /* the following two are parsed as ID_FQDN, so no match */ + ck_assert(id_matches(a, "*strongswan.org", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*.org", ID_MATCH_NONE)); + ck_assert(id_matches(a, "moon@*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "**", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*", ID_MATCH_ANY)); + ck_assert(id_matches(a, "%any", ID_MATCH_ANY)); + a->destroy(a); + + a = identification_create_from_string("vpn.strongswan.org"); + + ck_assert(id_matches(a, "vpn.strongswan.org", ID_MATCH_PERFECT)); + ck_assert(id_matches(a, "*.strongswan.org", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "*strongswan.org", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "*.org", ID_MATCH_ONE_WILDCARD)); + ck_assert(id_matches(a, "*.strongswan.*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*vpn.strongswan.org", ID_MATCH_NONE)); + ck_assert(id_matches(a, "vpn.strongswan.*", ID_MATCH_NONE)); + ck_assert(id_matches(a, "**", ID_MATCH_NONE)); + ck_assert(id_matches(a, "*", ID_MATCH_ANY)); + ck_assert(id_matches(a, "%any", ID_MATCH_ANY)); + a->destroy(a); +} +END_TEST + /******************************************************************************* * identification part enumeration */ @@ -184,6 +644,28 @@ START_TEST(test_contains_wildcards) } END_TEST +/******************************************************************************* + * clone + */ + +START_TEST(test_clone) +{ + identification_t *a, *b; + chunk_t a_enc, b_enc; + + a = identification_create_from_string("moon@strongswan.org"); + a_enc = a->get_encoding(a); + b = a->clone(a); + ck_assert(b != NULL); + ck_assert(a != b); + b_enc = b->get_encoding(b); + ck_assert(a_enc.ptr != b_enc.ptr); + ck_assert(chunk_equals(a_enc, b_enc)); + a->destroy(a); + b->destroy(b); +} +END_TEST + Suite *identification_suite_create() { Suite *s; @@ -191,12 +673,30 @@ Suite *identification_suite_create() s = suite_create("identification"); + tc = tcase_create("create"); + tcase_add_test(tc, test_from_encoding); + tcase_add_test(tc, test_from_data); + tcase_add_test(tc, test_from_sockaddr); + tcase_add_loop_test(tc, test_from_string, 0, countof(string_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("printf_hook"); + tcase_add_test(tc, test_printf_hook); + tcase_add_test(tc, test_printf_hook_width); + suite_add_tcase(s, tc); + tc = tcase_create("equals"); tcase_add_test(tc, test_equals); + tcase_add_test(tc, test_equals_any); + tcase_add_test(tc, test_equals_binary); + tcase_add_test(tc, test_equals_fqdn); suite_add_tcase(s, tc); tc = tcase_create("matches"); tcase_add_test(tc, test_matches); + tcase_add_test(tc, test_matches_any); + tcase_add_test(tc, test_matches_binary); + tcase_add_test(tc, test_matches_string); suite_add_tcase(s, tc); tc = tcase_create("part enumeration"); @@ -207,5 +707,9 @@ Suite *identification_suite_create() tcase_add_test(tc, test_contains_wildcards); suite_add_tcase(s, tc); + tc = tcase_create("clone"); + tcase_add_test(tc, test_clone); + suite_add_tcase(s, tc); + return s; } From 9947a1f2f41cbbbbf545f23fb7f5e718117d4dd0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 3 Jun 2013 18:45:57 +0200 Subject: [PATCH 40/48] Gracefully handle NULL as argument for enum_from_name() --- src/libstrongswan/utils/enum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c index 9b3c4d566..3db9a34e0 100644 --- a/src/libstrongswan/utils/enum.c +++ b/src/libstrongswan/utils/enum.c @@ -47,7 +47,7 @@ int enum_from_name(enum_name_t *e, char *name) for (i = 0; i < count; i++) { - if (strcaseeq(name, e->names[i])) + if (name && strcaseeq(name, e->names[i])) { return e->first + i; } From 80d9a9b722bad15597ab44bc73a09743139cd304 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 3 Jun 2013 18:58:14 +0200 Subject: [PATCH 41/48] Added tests for utils/enum.c --- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_enum.c | 248 ++++++++++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 4 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_enum.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 5e3a2526d..babbb285d 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,7 +5,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_chunk.c test_hashtable.c test_identification.c \ + test_chunk.c test_enum.c test_hashtable.c test_identification.c \ test_threading.c test_utils.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_enum.c b/src/libstrongswan/tests/test_enum.c new file mode 100644 index 000000000..66d5435ba --- /dev/null +++ b/src/libstrongswan/tests/test_enum.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include +#include + +/******************************************************************************* + * continuous enum + */ +enum { + CONT1, + CONT2, + CONT3, + CONT4, + CONT5, +} test_enum_cont; + +/* can't be static */ +enum_name_t *test_enum_cont_names; + +ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5, + "CONT1", "CONT2", "CONT3", "CONT4", "CONT5"); +ENUM_END(test_enum_cont_names, CONT5); + +/******************************************************************************* + * split enum + */ +enum { + SPLIT1 = 1, + SPLIT2, + SPLIT3 = 5, + SPLIT4, + SPLIT5 = 255, +} test_enum_split; + +/* can't be static */ +enum_name_t *test_enum_split_names; + +ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2, + "SPLIT1", "SPLIT2"); +ENUM_NEXT(test_enum_split_names, SPLIT3, SPLIT4, SPLIT2, + "SPLIT3", "SPLIT4"); +ENUM_NEXT(test_enum_split_names, SPLIT5, SPLIT5, SPLIT4, + "SPLIT5"); +ENUM_END(test_enum_split_names, SPLIT5); + +/******************************************************************************* + * enum_to_name + */ + +static struct { + int val; + char *str; +} name_tests_cont[] = { + {-1, NULL}, + {CONT1, "CONT1"}, + {CONT2, "CONT2"}, + {CONT3, "CONT3"}, + {CONT4, "CONT4"}, + {CONT5, "CONT5"}, + {5, NULL}, +}, name_tests_split[] = { + {-1, NULL}, + {0, NULL}, + {SPLIT1, "SPLIT1"}, + {SPLIT2, "SPLIT2"}, + {3, NULL}, + {4, NULL}, + {SPLIT3, "SPLIT3"}, + {SPLIT4, "SPLIT4"}, + {7, NULL}, + {254, NULL}, + {SPLIT5, "SPLIT5"}, + {256, NULL}, +}; + +START_TEST(test_enum_to_name_cont) +{ + char *str = enum_to_name(test_enum_cont_names, name_tests_cont[_i].val); + if (str) + { + ck_assert_str_eq(str, name_tests_cont[_i].str); + } + else + { + ck_assert(str == name_tests_cont[_i].str); + } +} +END_TEST + +START_TEST(test_enum_to_name_split) +{ + char *str = enum_to_name(test_enum_split_names, name_tests_split[_i].val); + if (str) + { + ck_assert_str_eq(str, name_tests_split[_i].str); + } + else + { + ck_assert(str == name_tests_split[_i].str); + } +} +END_TEST + +/******************************************************************************* + * enum_from_name + */ + +static struct { + int val; + char *str; +} enum_tests_cont[] = { + {CONT1, "CONT1"}, + {CONT2, "CONT2"}, + {CONT2, "CoNt2"}, + {CONT3, "CONT3"}, + {CONT4, "CONT4"}, + {CONT5, "CONT5"}, + {-1, "asdf"}, + {-1, ""}, + {-1, NULL}, +}, enum_tests_split[] = { + {SPLIT1, "SPLIT1"}, + {SPLIT1, "split1"}, + {SPLIT2, "SPLIT2"}, + {SPLIT2, "SpLiT2"}, + {SPLIT3, "SPLIT3"}, + {SPLIT4, "SPLIT4"}, + {SPLIT5, "SPLIT5"}, + {-1, "asdf"}, + {-1, ""}, + {-1, NULL}, +}; + +START_TEST(test_enum_from_name_cont) +{ + int val = enum_from_name(test_enum_cont_names, enum_tests_cont[_i].str); + ck_assert_int_eq(val, enum_tests_cont[_i].val); +} +END_TEST + +START_TEST(test_enum_from_name_split) +{ + int val = enum_from_name(test_enum_split_names, enum_tests_split[_i].str); + ck_assert_int_eq(val, enum_tests_split[_i].val); +} +END_TEST + +/******************************************************************************* + * enum_printf_hook + */ + +static struct { + int val; + char *str; +} printf_tests_cont[] = { + {-1, "(-1)"}, + {CONT1, "CONT1"}, + {CONT2, "CONT2"}, + {CONT3, "CONT3"}, + {CONT4, "CONT4"}, + {CONT5, "CONT5"}, + {5, "(5)"}, +}, printf_tests_split[] = { + {-1, "(-1)"}, + {0, "(0)"}, + {SPLIT1, "SPLIT1"}, + {SPLIT2, "SPLIT2"}, + {3, "(3)"}, + {4, "(4)"}, + {SPLIT3, "SPLIT3"}, + {SPLIT4, "SPLIT4"}, + {7, "(7)"}, + {254, "(254)"}, + {SPLIT5, "SPLIT5"}, + {256, "(256)"}, +}; + +START_TEST(test_enum_printf_hook_cont) +{ + char buf[128]; + + snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, printf_tests_cont[_i].val); + ck_assert_str_eq(printf_tests_cont[_i].str, buf); +} +END_TEST + +START_TEST(test_enum_printf_hook_split) +{ + char buf[128]; + + snprintf(buf, sizeof(buf), "%N", test_enum_split_names, printf_tests_split[_i].val); + ck_assert_str_eq(printf_tests_split[_i].str, buf); +} +END_TEST + +START_TEST(test_enum_printf_hook_width) +{ + char buf[128]; + + snprintf(buf, sizeof(buf), "%10N", test_enum_cont_names, CONT1); + ck_assert_str_eq(" CONT1", buf); + snprintf(buf, sizeof(buf), "%-*N", 10, test_enum_cont_names, CONT2); + ck_assert_str_eq("CONT2 ", buf); + snprintf(buf, sizeof(buf), "%3N", test_enum_cont_names, CONT3); + ck_assert_str_eq("CONT3", buf); +} +END_TEST + +Suite *enum_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("enum"); + + tc = tcase_create("enum_to_name"); + tcase_add_loop_test(tc, test_enum_to_name_cont, 0, countof(name_tests_cont)); + tcase_add_loop_test(tc, test_enum_to_name_split, 0, countof(name_tests_split)); + suite_add_tcase(s, tc); + + tc = tcase_create("enum_from_name"); + tcase_add_loop_test(tc, test_enum_from_name_cont, 0, countof(enum_tests_cont)); + tcase_add_loop_test(tc, test_enum_from_name_split, 0, countof(enum_tests_split)); + suite_add_tcase(s, tc); + + tc = tcase_create("enum_printf_hook"); + tcase_add_loop_test(tc, test_enum_printf_hook_cont, 0, countof(printf_tests_cont)); + tcase_add_loop_test(tc, test_enum_printf_hook_split, 0, countof(printf_tests_split)); + tcase_add_test(tc, test_enum_printf_hook_width); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index d830efded..f00226ab8 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -33,6 +33,7 @@ int main() sr = srunner_create(NULL); srunner_add_suite(sr, chunk_suite_create()); + srunner_add_suite(sr, enum_suite_create()); srunner_add_suite(sr, enumerator_suite_create()); srunner_add_suite(sr, linked_list_suite_create()); srunner_add_suite(sr, linked_list_enumerator_suite_create()); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index a5529fe1d..3a6253ae2 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -19,6 +19,7 @@ #include Suite *chunk_suite_create(); +Suite *enum_suite_create(); Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); From 01e15ab5c7e96eda80954b0a189aa43bffff98ec Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 4 Jun 2013 16:21:48 +0200 Subject: [PATCH 42/48] Add getter for the number of leaks to leak_detective_t --- src/libstrongswan/utils/leak_detective.c | 18 ++++++++++++++++-- src/libstrongswan/utils/leak_detective.h | 7 +++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 4f3c9f78b..9d9062203 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -589,7 +589,7 @@ static int print_traces(private_leak_detective_t *this, enumerator = entries->create_enumerator(entries); while (enumerator->enumerate(enumerator, NULL, &entry)) { - if (!thresh || entry->bytes >= thresh) + if (out && (!thresh || entry->bytes >= thresh)) { fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n", entry->bytes, entry->count, entry->bytes / entry->count); @@ -609,7 +609,7 @@ METHOD(leak_detective_t, report, void, { if (lib->leak_detective) { - int leaks = 0, whitelisted = 0; + int leaks, whitelisted = 0; leaks = print_traces(this, stderr, 0, detailed, &whitelisted); switch (leaks) @@ -632,6 +632,19 @@ METHOD(leak_detective_t, report, void, } } +METHOD(leak_detective_t, leaks, int, + private_leak_detective_t *this) +{ + if (lib->leak_detective) + { + int leaks, whitelisted = 0; + + leaks = print_traces(this, NULL, 0, FALSE, &whitelisted); + return leaks; + } + return 0; +} + METHOD(leak_detective_t, set_state, bool, private_leak_detective_t *this, bool enable) { @@ -885,6 +898,7 @@ leak_detective_t *leak_detective_create() INIT(this, .public = { .report = _report, + .leaks = _leaks, .usage = _usage, .set_state = _set_state, .destroy = _destroy, diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index 55d7e44d9..6a39aef06 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -42,6 +42,13 @@ struct leak_detective_t { */ void (*report)(leak_detective_t *this, bool detailed); + /** + * Number of detected leaks. + * + * @return number of leaks + */ + int (*leaks)(leak_detective_t *this); + /** * Report current memory usage to out. * From b4029a4aae567851c414194dbf99040f27fb16e5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 4 Jun 2013 16:25:22 +0200 Subject: [PATCH 43/48] Added tests for bio_reader_t --- src/libstrongswan/tests/Makefile.am | 4 +- src/libstrongswan/tests/test_bio_reader.c | 458 ++++++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 4 +- src/libstrongswan/tests/test_runner.h | 1 + 4 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 src/libstrongswan/tests/test_bio_reader.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index babbb285d..067bbd24d 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,8 +5,8 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_chunk.c test_enum.c test_hashtable.c test_identification.c \ - test_threading.c test_utils.c + test_bio_reader.c test_chunk.c test_enum.c test_hashtable.c \ + test_identification.c test_threading.c test_utils.c test_runner_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ diff --git a/src/libstrongswan/tests/test_bio_reader.c b/src/libstrongswan/tests/test_bio_reader.c new file mode 100644 index 000000000..f2df1e260 --- /dev/null +++ b/src/libstrongswan/tests/test_bio_reader.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include + +/******************************************************************************* + * different integer reads + */ + +#define assert_integer_read(data, bits, val) ({ \ + bio_reader_t *reader = bio_reader_create(data); \ + typeof(val) i; \ + for (i = 0; reader->remaining(reader) >= (bits / 8); i++) \ + { \ + ck_assert(reader->read_uint##bits(reader, &val)); \ + ck_assert_int_eq(i, val); \ + } \ + ck_assert_int_eq(i, data.len / (bits / 8)); \ + ck_assert_int_eq(reader->remaining(reader), data.len % (bits / 8)); \ + ck_assert(!reader->read_uint##bits(reader, &val)); \ + reader->destroy(reader); \ +}) + +#define assert_integer_read_uneven(data, bits, val) ({ \ + int i; \ + for (i = 0; i <= bits / 8; i++, data.len++) \ + { \ + assert_integer_read(data, bits, val); \ + } \ +}) + +#define assert_basic_read(bits, val) ({ \ + chunk_t data; \ + data = chunk_empty; \ + assert_integer_read(data, bits, val); \ + data = chunk_alloca(bits / 8); \ + memset(data.ptr, 0, data.len); \ + data.len = 0; \ + assert_integer_read_uneven(data, bits, val); \ +}) + +#define assert_extended_read(data, bits, val) ({ \ + chunk_t extended = chunk_alloca(data.len + bits / 8); \ + memset(extended.ptr, 0, extended.len); \ + extended.ptr[extended.len - 1] = data.len / (bits / 8); \ + memcpy(extended.ptr, data.ptr, data.len); \ + extended.len = data.len; \ + assert_integer_read_uneven(extended, bits, val); \ +}) + +START_TEST(test_read_uint8) +{ + chunk_t data = chunk_from_chars(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + u_int8_t val; + + assert_integer_read(data, 8, val); + assert_basic_read(8, val); + assert_extended_read(data, 8, val); +} +END_TEST + +START_TEST(test_read_uint16) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03); + u_int16_t val; + + assert_integer_read(data, 16, val); + assert_basic_read(16, val); + assert_extended_read(data, 16, val); +} +END_TEST + +START_TEST(test_read_uint24) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03); + u_int32_t val; + + assert_integer_read(data, 24, val); + assert_basic_read(24, val); + assert_extended_read(data, 24, val); +} +END_TEST + +START_TEST(test_read_uint32) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03); + u_int32_t val; + + assert_integer_read(data, 32, val); + assert_basic_read(32, val); + assert_extended_read(data, 32, val); +} +END_TEST + +START_TEST(test_read_uint64) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03); + u_int64_t val; + + assert_integer_read(data, 64, val); + assert_basic_read(64, val); + assert_extended_read(data, 64, val); +} +END_TEST + +/******************************************************************************* + * different integer reads from the end of a buffer + */ + +#define assert_integer_read_end(data, bits, val) ({ \ + bio_reader_t *reader = bio_reader_create(data); \ + typeof(val) i; \ + for (i = 0; reader->remaining(reader) >= (bits / 8); i++) \ + { \ + ck_assert(reader->read_uint##bits##_end(reader, &val)); \ + ck_assert_int_eq(i, val); \ + } \ + ck_assert_int_eq(i, data.len / (bits / 8)); \ + ck_assert_int_eq(reader->remaining(reader), data.len % (bits / 8)); \ + ck_assert(!reader->read_uint##bits##_end(reader, &val)); \ + reader->destroy(reader); \ +}) + +#define assert_integer_read_end_uneven(data, bits, val) ({ \ + int i; \ + data.ptr += bits / 8; \ + for (i = 0; i <= bits / 8; i++, data.ptr--, data.len++) \ + { \ + assert_integer_read_end(data, bits, val); \ + } \ +}) + +#define assert_basic_read_end(bits, val) ({ \ + chunk_t data; \ + data = chunk_empty; \ + assert_integer_read_end(data, bits, val); \ + data = chunk_alloca(bits / 8); \ + memset(data.ptr, 0, data.len); \ + data.len = 0; \ + assert_integer_read_end_uneven(data, bits, val); \ +}) + +#define assert_extended_read_end(data, bits, val) ({ \ + chunk_t extended = chunk_alloca(data.len + bits / 8); \ + memset(extended.ptr, 0, extended.len); \ + extended.ptr[bits / 8 - 1] = data.len / (bits / 8); \ + memcpy(extended.ptr + bits / 8, data.ptr, data.len); \ + extended.len = data.len; \ + assert_integer_read_end_uneven(extended, bits, val); \ +}) + +START_TEST(test_read_uint8_end) +{ + chunk_t data = chunk_from_chars(0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00); + u_int8_t val; + + assert_integer_read_end(data, 8, val); + assert_basic_read_end(8, val); + assert_extended_read_end(data, 8, val); +} +END_TEST + +START_TEST(test_read_uint16_end) +{ + chunk_t data = chunk_from_chars(0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00); + u_int16_t val; + + assert_integer_read_end(data, 16, val); + assert_basic_read_end(16, val); + assert_extended_read_end(data, 16, val); +} +END_TEST + +START_TEST(test_read_uint24_end) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00); + u_int32_t val; + + assert_integer_read_end(data, 24, val); + assert_basic_read_end(24, val); + assert_extended_read_end(data, 24, val); +} +END_TEST + +START_TEST(test_read_uint32_end) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00); + u_int32_t val; + + assert_integer_read_end(data, 32, val); + assert_basic_read_end(32, val); + assert_extended_read_end(data, 32, val); +} +END_TEST + +START_TEST(test_read_uint64_end) +{ + chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + u_int64_t val; + + assert_integer_read_end(data, 64, val); + assert_basic_read_end(64, val); + assert_extended_read_end(data, 64, val); +} +END_TEST + +/******************************************************************************* + * read data + */ + +static inline void assert_reader_after_read(bio_reader_t *reader, chunk_t data) +{ + chunk_t peek; + + ck_assert_int_eq(reader->remaining(reader), data.len); + peek = reader->peek(reader); + ck_assert_int_eq(reader->remaining(reader), data.len); + ck_assert(peek.ptr == data.ptr); + data.ptr != NULL ? ck_assert(chunk_equals(peek, data)) + : ck_assert(peek.ptr == NULL); +} + +START_TEST(test_read_data) +{ + chunk_t read, data = chunk_from_chars(0x00, 0x00, 0x00, 0x00); + bio_reader_t *reader; + + reader = bio_reader_create(chunk_empty); + ck_assert_int_eq(reader->remaining(reader), 0); + ck_assert(reader->read_data(reader, 0, &read)); + ck_assert(!reader->read_data(reader, 1, &read)); + reader->destroy(reader); + + reader = bio_reader_create(data); + ck_assert(reader->read_data(reader, 0, &read)); + ck_assert_int_eq(read.len, 0); + ck_assert(read.ptr == data.ptr); + assert_reader_after_read(reader, data); + + ck_assert(reader->read_data(reader, 1, &read)); + ck_assert_int_eq(read.len, 1); + ck_assert(read.ptr == data.ptr); + assert_reader_after_read(reader, chunk_skip(data, 1)); + + ck_assert(reader->read_data(reader, 2, &read)); + ck_assert_int_eq(read.len, 2); + ck_assert(read.ptr == data.ptr + 1); + assert_reader_after_read(reader, chunk_skip(data, 3)); + + ck_assert(!reader->read_data(reader, 2, &read)); + ck_assert(reader->read_data(reader, 1, &read)); + ck_assert_int_eq(read.len, 1); + ck_assert(read.ptr == data.ptr + 3); + assert_reader_after_read(reader, chunk_skip(data, 4)); + + ck_assert_int_eq(reader->remaining(reader), 0); + ck_assert(reader->read_data(reader, 0, &read)); + ck_assert(!reader->read_data(reader, 1, &read)); + reader->destroy(reader); +} +END_TEST + +START_TEST(test_read_data_end) +{ + chunk_t read, data = chunk_from_chars(0x00, 0x00, 0x00, 0x00); + bio_reader_t *reader; + + reader = bio_reader_create(chunk_empty); + ck_assert_int_eq(reader->remaining(reader), 0); + ck_assert(reader->read_data_end(reader, 0, &read)); + ck_assert(!reader->read_data_end(reader, 1, &read)); + reader->destroy(reader); + + reader = bio_reader_create(data); + ck_assert(reader->read_data_end(reader, 0, &read)); + ck_assert_int_eq(read.len, 0); + ck_assert(read.ptr == data.ptr + data.len); + assert_reader_after_read(reader, data); + + ck_assert(reader->read_data_end(reader, 1, &read)); + ck_assert_int_eq(read.len, 1); + data.len--; + ck_assert(read.ptr == data.ptr + data.len); + assert_reader_after_read(reader, data); + + ck_assert(reader->read_data_end(reader, 2, &read)); + ck_assert_int_eq(read.len, 2); + data.len -= 2; + ck_assert(read.ptr == data.ptr + data.len); + assert_reader_after_read(reader, data); + + ck_assert(!reader->read_data(reader, 2, &read)); + ck_assert(reader->read_data(reader, 1, &read)); + ck_assert_int_eq(read.len, 1); + ck_assert(read.ptr == data.ptr); + assert_reader_after_read(reader, chunk_empty); + + ck_assert_int_eq(reader->remaining(reader), 0); + ck_assert(reader->read_data(reader, 0, &read)); + ck_assert(!reader->read_data(reader, 1, &read)); + reader->destroy(reader); +} +END_TEST + +/******************************************************************************* + * read length followed by data + */ + +#define assert_read_data_len(bits) ({ \ + bio_reader_t *reader; \ + chunk_t read, data; \ + int i, len = bits / 8; \ + data = chunk_empty; \ + reader = bio_reader_create(data); \ + ck_assert(!reader->read_data##bits(reader, &read)); \ + reader->destroy(reader); \ + data = chunk_alloca(len + 8); \ + memset(data.ptr, 0, data.len); \ + for (i = 0; i <= 8; i++) \ + { \ + data.ptr[len - 1] = i; \ + data.len = len + i; \ + reader = bio_reader_create(data); \ + ck_assert(reader->read_data##bits(reader, &read)); \ + ck_assert_int_eq(reader->remaining(reader), 0); \ + ck_assert_int_eq(read.len, i); \ + ck_assert((!read.ptr && !read.len) || (read.ptr == data.ptr + len)); \ + reader->destroy(reader); \ + } \ + data.ptr[len - 1] = i; \ + reader = bio_reader_create(data); \ + ck_assert(!reader->read_data##bits(reader, &read)); \ + reader->destroy(reader); \ +}) + +START_TEST(test_read_data8) +{ + assert_read_data_len(8); +} +END_TEST + +START_TEST(test_read_data16) +{ + assert_read_data_len(16); +} +END_TEST + +START_TEST(test_read_data24) +{ + assert_read_data_len(24); +} +END_TEST + +START_TEST(test_read_data32) +{ + assert_read_data_len(32); +} +END_TEST + +/******************************************************************************* + * test constructors + */ + +START_TEST(test_create) +{ + chunk_t data = chunk_from_str("foobar"); + bio_reader_t *reader; + + lib->leak_detective->set_state(lib->leak_detective, TRUE); + + data = chunk_clone(data); + reader = bio_reader_create(data); + reader->destroy(reader); + chunk_free(&data); + + ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); +} +END_TEST + +START_TEST(test_create_own) +{ + chunk_t data = chunk_from_str("foobar"); + bio_reader_t *reader; + + lib->leak_detective->set_state(lib->leak_detective, TRUE); + + data = chunk_clone(data); + reader = bio_reader_create_own(data); + reader->destroy(reader); + + ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); +} +END_TEST + +Suite *bio_reader_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("bio_reader"); + + tc = tcase_create("integer reads"); + tcase_add_test(tc, test_read_uint8); + tcase_add_test(tc, test_read_uint16); + tcase_add_test(tc, test_read_uint24); + tcase_add_test(tc, test_read_uint32); + tcase_add_test(tc, test_read_uint64); + suite_add_tcase(s, tc); + + tc = tcase_create("integer reads from end"); + tcase_add_test(tc, test_read_uint8_end); + tcase_add_test(tc, test_read_uint16_end); + tcase_add_test(tc, test_read_uint24_end); + tcase_add_test(tc, test_read_uint32_end); + tcase_add_test(tc, test_read_uint64_end); + suite_add_tcase(s, tc); + + tc = tcase_create("data reads and peek"); + tcase_add_test(tc, test_read_data); + tcase_add_test(tc, test_read_data_end); + suite_add_tcase(s, tc); + + tc = tcase_create("data length reads"); + tcase_add_test(tc, test_read_data8); + tcase_add_test(tc, test_read_data16); + tcase_add_test(tc, test_read_data24); + tcase_add_test(tc, test_read_data32); + suite_add_tcase(s, tc); + + tc = tcase_create("constructors"); + tcase_add_test(tc, test_create); + tcase_add_test(tc, test_create_own); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index f00226ab8..1af3d6635 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -24,7 +24,8 @@ int main() SRunner *sr; int nf; - /* if a test fails there is no cleanup, so disable leak detective */ + /* test cases are forked and there is no cleanup, so disable leak detective. + * can be enabled for individual tests with leak_detective_t.set_state */ setenv("LEAK_DETECTIVE_DISABLE", "1", 1); /* redirect all output to stderr (to redirect make's stdout to /dev/null) */ dup2(2, 1); @@ -32,6 +33,7 @@ int main() library_init(NULL); sr = srunner_create(NULL); + srunner_add_suite(sr, bio_reader_suite_create()); srunner_add_suite(sr, chunk_suite_create()); srunner_add_suite(sr, enum_suite_create()); srunner_add_suite(sr, enumerator_suite_create()); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 3a6253ae2..8798b620e 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -18,6 +18,7 @@ #include +Suite *bio_reader_suite_create(); Suite *chunk_suite_create(); Suite *enum_suite_create(); Suite *enumerator_suite_create(); From eeb73dec7961f56cadd92c5d56a3a7009dfff22d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 4 Jun 2013 17:29:40 +0200 Subject: [PATCH 44/48] Ensure buffer in bio_writer_t is properly increased The previous code was problematic if bufsize/increase was smaller than 8 and an u_int64_t was written when the buffer was too small. Also, for large chunks and small bufsizes realloc() was called several times instead of just once. --- src/libstrongswan/bio/bio_writer.c | 78 +++++++++++------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/src/libstrongswan/bio/bio_writer.c b/src/libstrongswan/bio/bio_writer.c index 8576843ee..152d9ce22 100644 --- a/src/libstrongswan/bio/bio_writer.c +++ b/src/libstrongswan/bio/bio_writer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2013 Tobias Brunner * Hochschule fuer Technik Rapperswil * * Copyright (C) 2010 Martin Willi @@ -47,21 +47,27 @@ struct private_bio_writer_t { }; /** - * Increase buffer size + * Increase buffer size, if required */ -static void increase(private_bio_writer_t *this) +static inline void increase(private_bio_writer_t *this, size_t required) { - this->buf.len += this->increase; - this->buf.ptr = realloc(this->buf.ptr, this->buf.len); + bool inc = FALSE; + + while (this->used + required > this->buf.len) + { + this->buf.len += this->increase; + inc = TRUE; + } + if (inc) + { + this->buf.ptr = realloc(this->buf.ptr, this->buf.len); + } } METHOD(bio_writer_t, write_uint8, void, private_bio_writer_t *this, u_int8_t value) { - if (this->used + 1 > this->buf.len) - { - increase(this); - } + increase(this, 1); this->buf.ptr[this->used] = value; this->used += 1; } @@ -69,10 +75,7 @@ METHOD(bio_writer_t, write_uint8, void, METHOD(bio_writer_t, write_uint16, void, private_bio_writer_t *this, u_int16_t value) { - if (this->used + 2 > this->buf.len) - { - increase(this); - } + increase(this, 2); htoun16(this->buf.ptr + this->used, value); this->used += 2; } @@ -80,10 +83,7 @@ METHOD(bio_writer_t, write_uint16, void, METHOD(bio_writer_t, write_uint24, void, private_bio_writer_t *this, u_int32_t value) { - if (this->used + 3 > this->buf.len) - { - increase(this); - } + increase(this, 3); value = htonl(value); memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3); this->used += 3; @@ -92,10 +92,7 @@ METHOD(bio_writer_t, write_uint24, void, METHOD(bio_writer_t, write_uint32, void, private_bio_writer_t *this, u_int32_t value) { - if (this->used + 4 > this->buf.len) - { - increase(this); - } + increase(this, 4); htoun32(this->buf.ptr + this->used, value); this->used += 4; } @@ -103,10 +100,7 @@ METHOD(bio_writer_t, write_uint32, void, METHOD(bio_writer_t, write_uint64, void, private_bio_writer_t *this, u_int64_t value) { - if (this->used + 8 > this->buf.len) - { - increase(this); - } + increase(this, 8); htoun64(this->buf.ptr + this->used, value); this->used += 8; } @@ -114,10 +108,7 @@ METHOD(bio_writer_t, write_uint64, void, METHOD(bio_writer_t, write_data, void, private_bio_writer_t *this, chunk_t value) { - while (this->used + value.len > this->buf.len) - { - increase(this); - } + increase(this, value.len); memcpy(this->buf.ptr + this->used, value.ptr, value.len); this->used += value.len; } @@ -125,6 +116,7 @@ METHOD(bio_writer_t, write_data, void, METHOD(bio_writer_t, write_data8, void, private_bio_writer_t *this, chunk_t value) { + increase(this, 1 + value.len); write_uint8(this, value.len); write_data(this, value); } @@ -132,6 +124,7 @@ METHOD(bio_writer_t, write_data8, void, METHOD(bio_writer_t, write_data16, void, private_bio_writer_t *this, chunk_t value) { + increase(this, 2 + value.len); write_uint16(this, value.len); write_data(this, value); } @@ -139,6 +132,7 @@ METHOD(bio_writer_t, write_data16, void, METHOD(bio_writer_t, write_data24, void, private_bio_writer_t *this, chunk_t value) { + increase(this, 3 + value.len); write_uint24(this, value.len); write_data(this, value); } @@ -146,6 +140,7 @@ METHOD(bio_writer_t, write_data24, void, METHOD(bio_writer_t, write_data32, void, private_bio_writer_t *this, chunk_t value) { + increase(this, 4 + value.len); write_uint32(this, value.len); write_data(this, value); } @@ -153,10 +148,7 @@ METHOD(bio_writer_t, write_data32, void, METHOD(bio_writer_t, wrap8, void, private_bio_writer_t *this) { - if (this->used + 1 > this->buf.len) - { - increase(this); - } + increase(this, 1); memmove(this->buf.ptr + 1, this->buf.ptr, this->used); this->buf.ptr[0] = this->used; this->used += 1; @@ -165,10 +157,7 @@ METHOD(bio_writer_t, wrap8, void, METHOD(bio_writer_t, wrap16, void, private_bio_writer_t *this) { - if (this->used + 2 > this->buf.len) - { - increase(this); - } + increase(this, 2); memmove(this->buf.ptr + 2, this->buf.ptr, this->used); htoun16(this->buf.ptr, this->used); this->used += 2; @@ -179,10 +168,7 @@ METHOD(bio_writer_t, wrap24, void, { u_int32_t len; - if (this->used + 3 > this->buf.len) - { - increase(this); - } + increase(this, 3); memmove(this->buf.ptr + 3, this->buf.ptr, this->used); len = htonl(this->used); @@ -193,10 +179,7 @@ METHOD(bio_writer_t, wrap24, void, METHOD(bio_writer_t, wrap32, void, private_bio_writer_t *this) { - if (this->used + 4 > this->buf.len) - { - increase(this); - } + increase(this, 4); memmove(this->buf.ptr + 4, this->buf.ptr, this->used); htoun32(this->buf.ptr, this->used); this->used += 4; @@ -207,10 +190,7 @@ METHOD(bio_writer_t, skip, chunk_t, { chunk_t skipped; - while (this->used + len > this->buf.len) - { - increase(this); - } + increase(this, len); skipped = chunk_create(this->buf.ptr + this->used, len); this->used += len; return skipped; From 2b4902973b95bbd8063fab612c325e302c648d29 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 4 Jun 2013 18:29:06 +0200 Subject: [PATCH 45/48] Added tests for bio_writer_t --- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_bio_writer.c | 394 ++++++++++++++++++++++ src/libstrongswan/tests/test_runner.c | 1 + src/libstrongswan/tests/test_runner.h | 1 + 4 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/tests/test_bio_writer.c diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 067bbd24d..e0ac91e5d 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -5,7 +5,7 @@ check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ test_runner.c test_runner.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ - test_bio_reader.c test_chunk.c test_enum.c test_hashtable.c \ + test_bio_reader.c test_bio_writer.c test_chunk.c test_enum.c test_hashtable.c \ test_identification.c test_threading.c test_utils.c test_runner_CFLAGS = \ diff --git a/src/libstrongswan/tests/test_bio_writer.c b/src/libstrongswan/tests/test_bio_writer.c new file mode 100644 index 000000000..0bf4ab977 --- /dev/null +++ b/src/libstrongswan/tests/test_bio_writer.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include + +#include + +/******************************************************************************* + * different integer writes + */ + +static inline void verify_int_buffer(chunk_t data, int bits, int val) +{ + size_t i; + int len = bits / 8; + + ck_assert_int_eq(data.len, (val + 1) * len); + for (i = 0; i < data.len; i++) + { + (i + 1) % len ? ck_assert_int_eq(data.ptr[i], 0) + : ck_assert_int_eq(data.ptr[i], i / len); + } +} + +#define assert_integer_write(init, bits) ({ \ + int i; \ + bio_writer_t *writer = bio_writer_create(init); \ + for (i = 0; i < 16; i++) \ + { \ + writer->write_uint##bits(writer, i); \ + verify_int_buffer(writer->get_buf(writer), bits, i); \ + } \ + writer->destroy(writer); \ +}) + +START_TEST(test_write_uint8) +{ + /* use default buffer (and increase) size */ + assert_integer_write(0, 8); + /* force a resize by the given size */ + assert_integer_write(1, 8); +} +END_TEST + +START_TEST(test_write_uint16) +{ + assert_integer_write(0, 16); + assert_integer_write(1, 16); +} +END_TEST + +START_TEST(test_write_uint24) +{ + assert_integer_write(0, 24); + assert_integer_write(1, 24); +} +END_TEST + +START_TEST(test_write_uint32) +{ + assert_integer_write(0, 32); + assert_integer_write(1, 32); +} +END_TEST + +START_TEST(test_write_uint64) +{ + assert_integer_write(0, 64); + assert_integer_write(1, 64); +} +END_TEST + +/******************************************************************************* + * write data / skip + */ + +static inline void assert_writer_after_write(bio_writer_t *writer, int count) +{ + chunk_t buf; + size_t i; + + buf = writer->get_buf(writer); + ck_assert_int_eq(buf.len, count * 3); + for (i = 0; i < buf.len; i++) + { + ck_assert(buf.ptr[i] == i % 3); + } +} + +START_TEST(test_write_data) +{ + chunk_t buf, data = chunk_from_chars(0x00, 0x01, 0x02); + bio_writer_t *writer; + + /* no allocation, but default buffer size */ + writer = bio_writer_create(0); + buf = writer->get_buf(writer); + ck_assert_int_eq(buf.len, 0); + ck_assert(buf.ptr == NULL); + + writer->write_data(writer, chunk_empty); + buf = writer->get_buf(writer); + ck_assert_int_eq(buf.len, 0); + ck_assert(buf.ptr == NULL); + writer->destroy(writer); + + /* custom buffer size, initial buffer allocated */ + writer = bio_writer_create(1); + buf = writer->get_buf(writer); + ck_assert_int_eq(buf.len, 0); + ck_assert(buf.ptr != NULL); + + writer->write_data(writer, chunk_empty); + buf = writer->get_buf(writer); + ck_assert_int_eq(buf.len, 0); + ck_assert(buf.ptr != NULL); + writer->destroy(writer); + + writer = bio_writer_create(0); + + writer->write_data(writer, data); + assert_writer_after_write(writer, 1); + + writer->write_data(writer, data); + assert_writer_after_write(writer, 2); + + writer->write_data(writer, data); + assert_writer_after_write(writer, 3); + + writer->destroy(writer); +} +END_TEST + +START_TEST(test_skip) +{ + chunk_t skipped, buf, data = chunk_from_chars(0x00, 0x01, 0x02); + bio_writer_t *writer; + + writer = bio_writer_create(4); + skipped = writer->skip(writer, 3); + ck_assert_int_eq(skipped.len, 3); + buf = writer->get_buf(writer); + ck_assert(skipped.ptr == buf.ptr); + memset(skipped.ptr, 0, skipped.len); + + writer->write_data(writer, data); + buf = writer->get_buf(writer); + ck_assert(chunk_equals(buf, chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x01, 0x02))); + writer->destroy(writer); + + writer = bio_writer_create(1); + skipped = writer->skip(writer, 3); + memcpy(skipped.ptr, data.ptr, data.len); + + writer->write_data(writer, data); + assert_writer_after_write(writer, 2); + writer->destroy(writer); +} +END_TEST + +/******************************************************************************* + * write length followed by data + */ + +#define assert_write_data_len(init, bits) ({ \ + bio_writer_t *writer; \ + chunk_t buf, data; \ + int i, len = bits / 8; \ + writer = bio_writer_create(init); \ + writer->write_data##bits(writer, chunk_empty); \ + buf = writer->get_buf(writer); \ + ck_assert_int_eq(buf.len, len); \ + ck_assert_int_eq(buf.ptr[len - 1], 0); \ + writer->destroy(writer); \ + data = chunk_alloca(32); \ + memset(data.ptr, 0, data.len); \ + for (i = 0; i < 32; i++) \ + { \ + data.ptr[i] = i; \ + data.len = i; \ + writer = bio_writer_create(init); \ + writer->write_data##bits(writer, data); \ + buf = writer->get_buf(writer); \ + ck_assert_int_eq(buf.len, len + i); \ + ck_assert_int_eq(buf.ptr[len - 1], i); \ + ck_assert(chunk_equals(chunk_create(buf.ptr + len, buf.len - len), data)); \ + writer->destroy(writer); \ + } \ +}) + +START_TEST(test_write_data8) +{ + assert_write_data_len(0, 8); + assert_write_data_len(1, 8); +} +END_TEST + +START_TEST(test_write_data16) +{ + assert_write_data_len(0, 16); + assert_write_data_len(1, 16); +} +END_TEST + +START_TEST(test_write_data24) +{ + assert_write_data_len(0, 24); + assert_write_data_len(1, 24); +} +END_TEST + +START_TEST(test_write_data32) +{ + assert_write_data_len(0, 32); + assert_write_data_len(1, 32); +} +END_TEST + + +/******************************************************************************* + * add length header before current data + */ + +#define assert_wrap_data(init, bits) ({ \ + bio_writer_t *writer; \ + chunk_t buf, data; \ + int i, len = bits / 8; \ + writer = bio_writer_create(init); \ + writer->wrap##bits(writer); \ + buf = writer->get_buf(writer); \ + ck_assert_int_eq(buf.len, len); \ + ck_assert_int_eq(buf.ptr[len - 1], 0); \ + writer->destroy(writer); \ + data = chunk_alloca(32); \ + memset(data.ptr, 0, data.len); \ + for (i = 0; i < 32; i++) \ + { \ + data.ptr[i] = i; \ + data.len = i; \ + writer = bio_writer_create(init); \ + writer->write_data(writer, data); \ + writer->wrap##bits(writer); \ + buf = writer->get_buf(writer); \ + ck_assert_int_eq(buf.len, len + i); \ + ck_assert_int_eq(buf.ptr[len - 1], i); \ + ck_assert(chunk_equals(chunk_create(buf.ptr + len, buf.len - len), data)); \ + writer->wrap##bits(writer); \ + buf = writer->get_buf(writer); \ + ck_assert_int_eq(buf.len, 2 * len + i); \ + ck_assert_int_eq(buf.ptr[len - 1], len + i); \ + ck_assert(chunk_equals(chunk_create(buf.ptr + 2 * len, buf.len - 2 * len), data)); \ + writer->destroy(writer); \ + } \ +}) + +START_TEST(test_wrap8) +{ + assert_wrap_data(0, 8); + assert_wrap_data(1, 8); +} +END_TEST + +START_TEST(test_wrap16) +{ + assert_wrap_data(0, 16); + assert_wrap_data(1, 16); +} +END_TEST + +START_TEST(test_wrap24) +{ + assert_wrap_data(0, 24); + assert_wrap_data(1, 24); +} +END_TEST + +START_TEST(test_wrap32) +{ + assert_wrap_data(0, 32); + assert_wrap_data(1, 32); +} +END_TEST + +/******************************************************************************* + * test data extraction + */ + +START_TEST(test_get_buf) +{ + bio_writer_t *writer; + chunk_t data1, data2; + + lib->leak_detective->set_state(lib->leak_detective, TRUE); + + writer = bio_writer_create(0); + writer->write_uint8(writer, 1); + data1 = writer->get_buf(writer); + ck_assert_int_eq(data1.len, 1); + ck_assert(data1.ptr[0] == 1); + + data2 = writer->get_buf(writer); + ck_assert(chunk_equals(data1, data2)); + ck_assert(data1.ptr == data2.ptr); + writer->destroy(writer); + + ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); +} +END_TEST + +START_TEST(test_extract_buf) +{ + bio_writer_t *writer; + chunk_t data1, data2; + + lib->leak_detective->set_state(lib->leak_detective, TRUE); + + writer = bio_writer_create(0); + writer->write_uint8(writer, 1); + data1 = writer->extract_buf(writer); + ck_assert_int_eq(data1.len, 1); + ck_assert(data1.ptr[0] == 1); + + data2 = writer->get_buf(writer); + ck_assert_int_eq(data2.len, 0); + ck_assert(data2.ptr == NULL); + data2 = writer->extract_buf(writer); + ck_assert_int_eq(data2.len, 0); + ck_assert(data2.ptr == NULL); + + writer->write_uint8(writer, 1); + data2 = writer->get_buf(writer); + ck_assert(chunk_equals(data1, data2)); + ck_assert(data1.ptr != data2.ptr); + + writer->destroy(writer); + chunk_free(&data1); + + ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); +} +END_TEST + +Suite *bio_writer_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("bio_writer"); + + tc = tcase_create("integer writes"); + tcase_add_test(tc, test_write_uint8); + tcase_add_test(tc, test_write_uint16); + tcase_add_test(tc, test_write_uint24); + tcase_add_test(tc, test_write_uint32); + tcase_add_test(tc, test_write_uint64); + suite_add_tcase(s, tc); + + tc = tcase_create("data writes/skip"); + tcase_add_test(tc, test_write_data); + tcase_add_test(tc, test_skip); + suite_add_tcase(s, tc); + + tc = tcase_create("data length writes"); + tcase_add_test(tc, test_write_data8); + tcase_add_test(tc, test_write_data16); + tcase_add_test(tc, test_write_data24); + tcase_add_test(tc, test_write_data32); + suite_add_tcase(s, tc); + + tc = tcase_create("wrap writes"); + tcase_add_test(tc, test_wrap8); + tcase_add_test(tc, test_wrap16); + tcase_add_test(tc, test_wrap24); + tcase_add_test(tc, test_wrap32); + suite_add_tcase(s, tc); + + tc = tcase_create("get/extract"); + tcase_add_test(tc, test_get_buf); + tcase_add_test(tc, test_extract_buf); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 1af3d6635..5f3b2d397 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -34,6 +34,7 @@ int main() sr = srunner_create(NULL); srunner_add_suite(sr, bio_reader_suite_create()); + srunner_add_suite(sr, bio_writer_suite_create()); srunner_add_suite(sr, chunk_suite_create()); srunner_add_suite(sr, enum_suite_create()); srunner_add_suite(sr, enumerator_suite_create()); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 8798b620e..1fc985104 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -19,6 +19,7 @@ #include Suite *bio_reader_suite_create(); +Suite *bio_writer_suite_create(); Suite *chunk_suite_create(); Suite *enum_suite_create(); Suite *enumerator_suite_create(); From 95e9915074c8ac1f6eefa4d8d986de7a4bd7d2ca Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 5 Jun 2013 14:01:40 +0200 Subject: [PATCH 46/48] Enable leak detective for all test cases --- src/libstrongswan/tests/Makefile.am | 2 +- src/libstrongswan/tests/test_bio_reader.c | 2 +- src/libstrongswan/tests/test_bio_writer.c | 2 +- src/libstrongswan/tests/test_chunk.c | 2 +- src/libstrongswan/tests/test_enum.c | 2 +- src/libstrongswan/tests/test_enumerator.c | 8 +- src/libstrongswan/tests/test_hashtable.c | 8 +- src/libstrongswan/tests/test_identification.c | 2 +- src/libstrongswan/tests/test_linked_list.c | 8 +- .../tests/test_linked_list_enumerator.c | 8 +- src/libstrongswan/tests/test_runner.c | 2 +- src/libstrongswan/tests/test_suite.h | 99 +++++++++++++++++++ src/libstrongswan/tests/test_threading.c | 3 +- src/libstrongswan/tests/test_utils.c | 3 +- 14 files changed, 129 insertions(+), 22 deletions(-) create mode 100644 src/libstrongswan/tests/test_suite.h diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index e0ac91e5d..6b4ba2c55 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -3,7 +3,7 @@ TESTS = test_runner check_PROGRAMS = $(TESTS) test_runner_SOURCES = \ - test_runner.c test_runner.h \ + test_runner.c test_runner.h test_suite.h \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ test_bio_reader.c test_bio_writer.c test_chunk.c test_enum.c test_hashtable.c \ test_identification.c test_threading.c test_utils.c diff --git a/src/libstrongswan/tests/test_bio_reader.c b/src/libstrongswan/tests/test_bio_reader.c index f2df1e260..4f6f8cf59 100644 --- a/src/libstrongswan/tests/test_bio_reader.c +++ b/src/libstrongswan/tests/test_bio_reader.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include diff --git a/src/libstrongswan/tests/test_bio_writer.c b/src/libstrongswan/tests/test_bio_writer.c index 0bf4ab977..027606af2 100644 --- a/src/libstrongswan/tests/test_bio_writer.c +++ b/src/libstrongswan/tests/test_bio_writer.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include diff --git a/src/libstrongswan/tests/test_chunk.c b/src/libstrongswan/tests/test_chunk.c index 9c5115b13..5fa1c0b1d 100644 --- a/src/libstrongswan/tests/test_chunk.c +++ b/src/libstrongswan/tests/test_chunk.c @@ -15,7 +15,7 @@ */ -#include +#include "test_suite.h" #include diff --git a/src/libstrongswan/tests/test_enum.c b/src/libstrongswan/tests/test_enum.c index 66d5435ba..990d9cfad 100644 --- a/src/libstrongswan/tests/test_enum.c +++ b/src/libstrongswan/tests/test_enum.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include #include diff --git a/src/libstrongswan/tests/test_enumerator.c b/src/libstrongswan/tests/test_enumerator.c index 687e476c1..b5dde4650 100644 --- a/src/libstrongswan/tests/test_enumerator.c +++ b/src/libstrongswan/tests/test_enumerator.c @@ -14,7 +14,7 @@ * for more details. */ -#include +#include "test_suite.h" #include #include @@ -82,15 +82,17 @@ END_TEST static int destroy_data_called; -static void setup_destroy_data() +START_SETUP(setup_destroy_data) { destroy_data_called = 0; } +END_SETUP -static void teardown_destroy_data() +START_TEARDOWN(teardown_destroy_data) { ck_assert_int_eq(destroy_data_called, 1); } +END_TEARDOWN static void destroy_data(void *data) { diff --git a/src/libstrongswan/tests/test_hashtable.c b/src/libstrongswan/tests/test_hashtable.c index bee773535..8cc7bfe42 100644 --- a/src/libstrongswan/tests/test_hashtable.c +++ b/src/libstrongswan/tests/test_hashtable.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include #include @@ -38,17 +38,19 @@ static bool equals(char *key1, char *key2) static hashtable_t *ht; -static void setup_ht() +START_SETUP(setup_ht) { ht = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 0); ck_assert_int_eq(ht->get_count(ht), 0); } +END_SETUP -static void teardown_ht() +START_TEARDOWN(teardown_ht) { ht->destroy(ht); } +END_TEARDOWN /******************************************************************************* * put/get diff --git a/src/libstrongswan/tests/test_identification.c b/src/libstrongswan/tests/test_identification.c index d21d4c7fa..b0b3ce826 100644 --- a/src/libstrongswan/tests/test_identification.c +++ b/src/libstrongswan/tests/test_identification.c @@ -14,7 +14,7 @@ * for more details. */ -#include +#include "test_suite.h" #include diff --git a/src/libstrongswan/tests/test_linked_list.c b/src/libstrongswan/tests/test_linked_list.c index 32b5cd7c9..fc055bb7f 100644 --- a/src/libstrongswan/tests/test_linked_list.c +++ b/src/libstrongswan/tests/test_linked_list.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include @@ -23,7 +23,7 @@ static linked_list_t *list; -static void setup_list() +START_SETUP(setup_list) { void *x = NULL; @@ -32,11 +32,13 @@ static void setup_list() ck_assert(list->get_first(list, &x) == NOT_FOUND); ck_assert(list->get_last(list, &x) == NOT_FOUND); } +END_SETUP -static void teardown_list() +START_TEARDOWN(teardown_list) { list->destroy(list); } +END_TEARDOWN /******************************************************************************* * insert first/last diff --git a/src/libstrongswan/tests/test_linked_list_enumerator.c b/src/libstrongswan/tests/test_linked_list_enumerator.c index d44f7ab9f..338a38224 100644 --- a/src/libstrongswan/tests/test_linked_list_enumerator.c +++ b/src/libstrongswan/tests/test_linked_list_enumerator.c @@ -13,7 +13,7 @@ * for more details. */ -#include +#include "test_suite.h" #include @@ -23,17 +23,19 @@ static linked_list_t *list; -static void setup_list() +START_SETUP(setup_list) { list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4, (void*)5, NULL); ck_assert_int_eq(list->get_count(list), 5); } +END_SETUP -static void teardown_list() +START_TEARDOWN(teardown_list) { list->destroy(list); } +END_TEARDOWN /******************************************************************************* * enumeration diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 5f3b2d397..2cce42b27 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -25,7 +25,7 @@ int main() int nf; /* test cases are forked and there is no cleanup, so disable leak detective. - * can be enabled for individual tests with leak_detective_t.set_state */ + * if test_suite.h is included leak detective is enabled in test cases */ setenv("LEAK_DETECTIVE_DISABLE", "1", 1); /* redirect all output to stderr (to redirect make's stdout to /dev/null) */ dup2(2, 1); diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h new file mode 100644 index 000000000..616a50e3a --- /dev/null +++ b/src/libstrongswan/tests/test_suite.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#ifndef TEST_UTILS_H_ +#define TEST_UTILS_H_ + +#include +#include + +/** + * Used to mark test cases that use test fixtures. + */ +#define UNIT_TEST_FIXTURE_USED "UNIT_TEST_FIXTURE_USED" + +/** + * Check for memory leaks and fail if any are encountered. + */ +#define CHECK_FOR_LEAKS() do \ +{ \ + if (lib->leak_detective->leaks(lib->leak_detective)) { \ + lib->leak_detective->report(lib->leak_detective, TRUE); \ + } \ + ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); \ +} \ +while(0) + +/** + * Extended versions of the START|END_TEST macros that use leak detective. + * + * Since each test case runs in its own fork of the test runner the stuff + * allocated before the test starts is not freed, so leak detective is disabled + * by default to prevent false positives. By enabling it right when the test + * starts we at least capture leaks created by the tested objects/functions and + * the test case itself. This allows writing test cases for cleanup functions. + * + * To define test fixture with possibly allocated/destroyed memory that is + * allocated/freed in a test case use the START|END_SETUP|TEARDOWN macros. + */ +#undef START_TEST +#define START_TEST(name) \ +static void name (int _i CK_ATTRIBUTE_UNUSED) \ +{ \ + tcase_fn_start(""#name, __FILE__, __LINE__); \ + lib->leak_detective->set_state(lib->leak_detective, TRUE); + +#undef END_TEST +#define END_TEST \ + if (!lib->get(lib, UNIT_TEST_FIXTURE_USED)) \ + { \ + CHECK_FOR_LEAKS(); \ + } \ +} + +/** + * Define a function to setup a test fixture that can be used with the above + * macros. + */ +#define START_SETUP(name) \ +static void name() \ +{ \ + lib->set(lib, UNIT_TEST_FIXTURE_USED, (void*)TRUE); \ + lib->leak_detective->set_state(lib->leak_detective, TRUE); + +/** + * End a setup function + */ +#define END_SETUP } + +/** + * Define a function to teardown a test fixture that can be used with the above + * macros. + */ +#define START_TEARDOWN(name) \ +static void name() \ +{ + +/** + * End a teardown function + */ +#define END_TEARDOWN \ + if (lib->get(lib, UNIT_TEST_FIXTURE_USED)) \ + { \ + CHECK_FOR_LEAKS(); \ + } \ +} + +#endif /** TEST_UTILS_H_ */ diff --git a/src/libstrongswan/tests/test_threading.c b/src/libstrongswan/tests/test_threading.c index 1ffbcb6b0..0c768b3e2 100644 --- a/src/libstrongswan/tests/test_threading.c +++ b/src/libstrongswan/tests/test_threading.c @@ -14,10 +14,11 @@ * for more details. */ -#include #include #include +#include "test_suite.h" + #include /******************************************************************************* diff --git a/src/libstrongswan/tests/test_utils.c b/src/libstrongswan/tests/test_utils.c index 9efc77621..f7cb605fa 100644 --- a/src/libstrongswan/tests/test_utils.c +++ b/src/libstrongswan/tests/test_utils.c @@ -13,8 +13,7 @@ * for more details. */ - -#include +#include "test_suite.h" #include #include From f2eeb54e8bb1f40080463ee65747216eb2ea3505 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 5 Jun 2013 14:14:12 +0200 Subject: [PATCH 47/48] Remove explicit leak detective checks as these are now done for all tests --- src/libstrongswan/tests/test_bio_reader.c | 8 -------- src/libstrongswan/tests/test_bio_writer.c | 8 -------- 2 files changed, 16 deletions(-) diff --git a/src/libstrongswan/tests/test_bio_reader.c b/src/libstrongswan/tests/test_bio_reader.c index 4f6f8cf59..45b20db00 100644 --- a/src/libstrongswan/tests/test_bio_reader.c +++ b/src/libstrongswan/tests/test_bio_reader.c @@ -388,14 +388,10 @@ START_TEST(test_create) chunk_t data = chunk_from_str("foobar"); bio_reader_t *reader; - lib->leak_detective->set_state(lib->leak_detective, TRUE); - data = chunk_clone(data); reader = bio_reader_create(data); reader->destroy(reader); chunk_free(&data); - - ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); } END_TEST @@ -404,13 +400,9 @@ START_TEST(test_create_own) chunk_t data = chunk_from_str("foobar"); bio_reader_t *reader; - lib->leak_detective->set_state(lib->leak_detective, TRUE); - data = chunk_clone(data); reader = bio_reader_create_own(data); reader->destroy(reader); - - ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); } END_TEST diff --git a/src/libstrongswan/tests/test_bio_writer.c b/src/libstrongswan/tests/test_bio_writer.c index 027606af2..767f17996 100644 --- a/src/libstrongswan/tests/test_bio_writer.c +++ b/src/libstrongswan/tests/test_bio_writer.c @@ -302,8 +302,6 @@ START_TEST(test_get_buf) bio_writer_t *writer; chunk_t data1, data2; - lib->leak_detective->set_state(lib->leak_detective, TRUE); - writer = bio_writer_create(0); writer->write_uint8(writer, 1); data1 = writer->get_buf(writer); @@ -314,8 +312,6 @@ START_TEST(test_get_buf) ck_assert(chunk_equals(data1, data2)); ck_assert(data1.ptr == data2.ptr); writer->destroy(writer); - - ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); } END_TEST @@ -324,8 +320,6 @@ START_TEST(test_extract_buf) bio_writer_t *writer; chunk_t data1, data2; - lib->leak_detective->set_state(lib->leak_detective, TRUE); - writer = bio_writer_create(0); writer->write_uint8(writer, 1); data1 = writer->extract_buf(writer); @@ -346,8 +340,6 @@ START_TEST(test_extract_buf) writer->destroy(writer); chunk_free(&data1); - - ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); } END_TEST From bde35a6fb2da649abcf983435fcdb8642c6a3b79 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 5 Jun 2013 16:34:04 +0200 Subject: [PATCH 48/48] Suppress log messages during tests --- src/libstrongswan/tests/test_suite.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h index 616a50e3a..edf16f128 100644 --- a/src/libstrongswan/tests/test_suite.h +++ b/src/libstrongswan/tests/test_suite.h @@ -18,6 +18,7 @@ #include #include +#include /** * Used to mark test cases that use test fixtures. @@ -53,6 +54,7 @@ while(0) static void name (int _i CK_ATTRIBUTE_UNUSED) \ { \ tcase_fn_start(""#name, __FILE__, __LINE__); \ + dbg_default_set_level(LEVEL_SILENT); \ lib->leak_detective->set_state(lib->leak_detective, TRUE); #undef END_TEST