Adds a test runner and several test suites for libstrongswan.
Also adds an option to produce a test coverage report.
Several bugs were fixed in the process and chunk_hash() was replaced
with an improved implementation based on SipHash-2-4 (with a randomly
allocated key to prevent hash flooding attacks).
*.tar.bz2
*.tar.gz
.DS_Store
+coverage/
+*.gcno
+*.gcda
+*.gcov
\ No newline at end of file
- lex/flex
- yacc/bison
- gperf
+
+ Optionally:
- check
- - optionally Doxygen
+ - lcov/genhtml
+ - Doxygen
To check out the master branch, use:
apidoc : Doxyfile
doxygen
-clean-local:
- rm -rf apidoc
+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.cleaned.info
+ @echo "Coverage Report at $(top_builddir)/coverage/html" >&2
+
+coverage:
+ @$(MAKE) cov-reset
+ @$(MAKE) check
+ @$(MAKE) cov-report
+else
+coverage:
+ @echo "reconfigure with --enable-coverage"
+endif
+
+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
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.])
mediation=true
fi
+if test x$coverage = xtrue; then
+ unit_tests=true
+fi
+
# ===========================================
# check required libraries and header files
# ===========================================
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
# ===============================================
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)
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
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 \
tests/test_sqlite.c \
- tests/test_mutex.c \
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 \
- tests/test_id.c \
- tests/test_hashtable.c
+ tests/test_agent.c
libstrongswan_unit_tester_la_LDFLAGS = -module -avoid-version
* @{ @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)
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)
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)
/** @}*/
+++ /dev/null
-/*
- * Copyright (C) 2008 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <library.h>
-#include <daemon.h>
-
-/*******************************************************************************
- * Base64 encoding/decoding test
- ******************************************************************************/
-bool test_chunk_base64()
-{
- /* test vectors from RFC4648:
- *
- * BASE64("") = ""
- * BASE64("f") = "Zg=="
- * BASE64("fo") = "Zm8="
- * BASE64("foo") = "Zm9v"
- * BASE64("foob") = "Zm9vYg=="
- * BASE64("fooba") = "Zm9vYmE="
- * BASE64("foobar") = "Zm9vYmFy"
- */
-
- typedef struct {
- char *in;
- char *out;
- } testdata_t;
-
- testdata_t test[] = {
- {"", ""},
- {"f", "Zg=="},
- {"fo", "Zm8="},
- {"foo", "Zm9v"},
- {"foob", "Zm9vYg=="},
- {"fooba", "Zm9vYmE="},
- {"foobar", "Zm9vYmFy"},
- };
- int i;
-
- for (i = 0; i < countof(test); i++)
- {
- 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;
- }
- free(out.ptr);
- }
-
- for (i = 0; i < countof(test); i++)
- {
- 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;
- }
- free(out.ptr);
- }
- return TRUE;
-}
-
+++ /dev/null
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <collections/linked_list.h>
-
-
-/*******************************************************************************
- * 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;
-}
-
+++ /dev/null
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <library.h>
-#include <collections/hashtable.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <daemon.h>
-
-/*******************************************************************************
- * 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;
-}
-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
libstrongswan_la_LIBADD += plugins/test_vectors/libstrongswan-test-vectors.la
endif
endif
+
+if UNITTESTS
+if MONOLITHIC
+ SUBDIRS += .
+endif
+ SUBDIRS += tests
+endif
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010 Martin Willi
};
/**
- * 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;
}
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;
}
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;
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;
}
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;
}
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;
}
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);
}
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);
}
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);
}
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);
}
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;
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;
{
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);
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;
{
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;
}
}
- /* trim trailing characters/separators */
+ /* trim trailing characters */
pos--;
while (pos >= *token)
{
}
trim++;
}
- sep = this->sep;
- while (*sep)
- {
- if (*sep == *pos)
- {
- *(pos--) = '\0';
- break;
- }
- sep++;
- }
- if (!*trim && !*sep)
+ if (!*trim)
{
break;
}
* 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);
*/
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.
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.
--- /dev/null
+test_runner
--- /dev/null
+TESTS = test_runner
+
+check_PROGRAMS = $(TESTS)
+
+test_runner_SOURCES = \
+ 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
+
+test_runner_CFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ @COVERAGE_CFLAGS@ \
+ @CHECK_CFLAGS@
+
+test_runner_LDFLAGS = @COVERAGE_LDFLAGS@
+test_runner_LDADD = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ @CHECK_LIBS@
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <bio/bio_reader.h>
+
+/*******************************************************************************
+ * 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;
+
+ data = chunk_clone(data);
+ reader = bio_reader_create(data);
+ reader->destroy(reader);
+ chunk_free(&data);
+}
+END_TEST
+
+START_TEST(test_create_own)
+{
+ chunk_t data = chunk_from_str("foobar");
+ bio_reader_t *reader;
+
+ data = chunk_clone(data);
+ reader = bio_reader_create_own(data);
+ reader->destroy(reader);
+}
+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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <bio/bio_writer.h>
+
+/*******************************************************************************
+ * 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;
+
+ 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);
+}
+END_TEST
+
+START_TEST(test_extract_buf)
+{
+ bio_writer_t *writer;
+ chunk_t data1, data2;
+
+ 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);
+}
+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;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2008 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <utils/chunk.h>
+
+/*******************************************************************************
+ * 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 RFC 4648:
+ *
+ * BASE64("") = ""
+ * BASE64("f") = "Zg=="
+ * BASE64("fo") = "Zm8="
+ * BASE64("foo") = "Zm9v"
+ * BASE64("foob") = "Zm9vYg=="
+ * BASE64("fooba") = "Zm9vYmE="
+ * BASE64("foobar") = "Zm9vYmFy"
+ */
+ typedef struct {
+ char *in;
+ char *out;
+ } testdata_t;
+
+ testdata_t test[] = {
+ {"", ""},
+ {"f", "Zg=="},
+ {"fo", "Zm8="},
+ {"foo", "Zm9v"},
+ {"foob", "Zm9vYg=="},
+ {"fooba", "Zm9vYmE="},
+ {"foobar", "Zm9vYmFy"},
+ };
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_to_base64(chunk_create(test[i].in, strlen(test[i].in)), NULL);
+ 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_base64(chunk_create(test[i].out, strlen(test[i].out)), NULL);
+ fail_unless(strneq(out.ptr, test[i].in, out.len),
+ "base64 conversion error - should '%s', is %#B",
+ test[i].in, &out);
+ free(out.ptr);
+ }
+}
+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
+ */
+
+/**
+ * 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
+
+
+/*******************************************************************************
+ * 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;
+ TCase *tc;
+
+ s = suite_create("chunk");
+
+ 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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <utils/enum.h>
+#include <utils/utils.h>
+
+/*******************************************************************************
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <collections/enumerator.h>
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * 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
+
+/*******************************************************************************
+ * utilities for filtered, nested and cleaner tests
+ */
+
+static int destroy_data_called;
+
+START_SETUP(setup_destroy_data)
+{
+ destroy_data_called = 0;
+}
+END_SETUP
+
+START_TEARDOWN(teardown_destroy_data)
+{
+ ck_assert_int_eq(destroy_data_called, 1);
+}
+END_TEARDOWN
+
+static void destroy_data(void *data)
+{
+ fail_if(data != (void*)101, "data does not match '101' in destructor");
+ destroy_data_called++;
+}
+
+/*******************************************************************************
+ * 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;
+}
+
+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;
+ 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);
+ 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);
+}
+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);
+}
+
+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)
+{
+ 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();
+ 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);
+ ck_assert_int_eq(round, 6);
+
+ list->destroy(list);
+ l1->destroy(l1);
+ l2->destroy(l2);
+ l3->destroy(l3);
+}
+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;
+ 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_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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <collections/hashtable.h>
+#include <utils/chunk.h>
+
+/*******************************************************************************
+ * 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;
+
+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
+
+START_TEARDOWN(teardown_ht)
+{
+ ht->destroy(ht);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * 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
+ */
+
+static void do_remove(char *k1, char *k2, char *k3)
+{
+ 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);
+}
+
+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
+
+/*******************************************************************************
+ * 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);
+
+ 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);
+
+ 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
+ */
+
+static void do_remove_at(char *k1, char *k2, char *k3)
+{
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value, *key;
+ enumerator_t *enumerator;
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ 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))
+ {
+ 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);
+}
+
+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()
+{
+ 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);
+ tcase_add_test(tc, test_remove_one_bucket);
+ 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);
+ tcase_add_test(tc, test_remove_at_one_bucket);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <utils/identification.h>
+
+/*******************************************************************************
+ * 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
+ */
+
+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);
+ equals = equals && b->equals(b, a);
+ b->destroy(b);
+ return equals;
+}
+
+START_TEST(test_equals)
+{
+ identification_t *a;
+ chunk_t encoding, fuzzed;
+ int i;
+
+ /* this test also tests identification_create_from_string with DNs */
+ a = identification_create_from_string(
+ "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=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);
+
+ /* simple fuzzing, increment each byte of encoding */
+ for (i = 0; i < encoding.len; i++)
+ {
+ 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);
+ 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);
+ }
+
+ /* and decrement each byte of encoding */
+ for (i = 0; i < encoding.len; i++)
+ {
+ 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=moon@strongswan.org, CN=moon"));
+ a->destroy(a);
+ free(fuzzed.ptr);
+ }
+ free(encoding.ptr);
+}
+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
+ */
+
+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=moon@strongswan.org, CN=moon");
+
+ 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
+ */
+
+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
+
+/*******************************************************************************
+ * 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;
+ TCase *tc;
+
+ 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");
+ 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);
+
+ tc = tcase_create("clone");
+ tcase_add_test(tc, test_clone);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * test fixture
+ */
+
+static linked_list_t *list;
+
+START_SETUP(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);
+}
+END_SETUP
+
+START_TEARDOWN(teardown_list)
+{
+ list->destroy(list);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * 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
+
+/*******************************************************************************
+ * 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;
+ 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);
+
+ 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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * test fixture
+ */
+
+static linked_list_t *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
+
+START_TEARDOWN(teardown_list)
+{
+ list->destroy(list);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * enumeration
+ */
+
+START_TEST(test_enumerate)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ 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;
+ intptr_t x;
+ int round;
+
+ 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_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;
+ intptr_t x;
+ int round;
+
+ 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;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ if (x == _i)
+ {
+ 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 == _i && x != _i)
+ {
+ 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;
+ intptr_t x;
+ int round;
+
+ 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;
+ intptr_t 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;
+ intptr_t x, y;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ y = (intptr_t)list->replace(list, enumerator, (void*)(intptr_t)(6 - round));
+ ck_assert_int_eq(round, y);
+ 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_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;
+ intptr_t x;
+ int round;
+
+ 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;
+ intptr_t 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
+
+/*******************************************************************************
+ * 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;
+ 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_empty);
+ 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_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);
+
+ 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);
+
+ 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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <unistd.h>
+
+#include "test_runner.h"
+
+#include <library.h>
+
+int main()
+{
+ SRunner *sr;
+ int nf;
+
+ /* test cases are forked and there is no cleanup, so disable leak detective.
+ * 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);
+
+ library_init(NULL);
+
+ 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());
+ 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_add_suite(sr, threading_suite_create());
+ srunner_add_suite(sr, utils_suite_create());
+
+ srunner_run_all(sr, CK_NORMAL);
+ nf = srunner_ntests_failed(sr);
+
+ srunner_free(sr);
+ library_deinit();
+
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <check.h>
+
+Suite *bio_reader_suite_create();
+Suite *bio_writer_suite_create();
+Suite *chunk_suite_create();
+Suite *enum_suite_create();
+Suite *enumerator_suite_create();
+Suite *linked_list_suite_create();
+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_ */
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <check.h>
+#include <library.h>
+#include <utils/debug.h>
+
+/**
+ * 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__); \
+ dbg_default_set_level(LEVEL_SILENT); \
+ 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_ */
/*
+ * Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* for more details.
*/
-#include <library.h>
-#include <threading/mutex.h>
-
-#include <unistd.h>
#include <sched.h>
#include <pthread.h>
+#include "test_suite.h"
-static mutex_t *mutex;
+#include <threading/mutex.h>
-static int locked = 0;
+/*******************************************************************************
+ * recursive mutex test
+ */
-static bool failed = FALSE;
+#define THREADS 20
+
+static mutex_t *mutex;
-static pthread_barrier_t barrier;
+static pthread_barrier_t mutex_barrier;
-static void* run(void* null)
+static int mutex_locked = 0;
+
+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);
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);
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;
+}
--- /dev/null
+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_suite.h"
+
+#include <library.h>
+#include <utils/utils.h>
+
+/*******************************************************************************
+ * 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
+
+/*******************************************************************************
+ * 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;
+ TCase *tc;
+
+ s = suite_create("utils");
+
+ tc = tcase_create("objects");
+ 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;
+}
/*
- * 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
*/
#include <stdio.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <pthread.h>
#include <ctype.h>
#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.
*/
}
/**
- * Described in header.
- *
- * The implementation is based on Paul Hsieh's SuperFastHash:
- * http://www.azillionmonkeys.com/qed/hash.html
+ * Helper functions for chunk_mac()
*/
-u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
+static inline u_int64_t sipget(u_char *in)
{
- u_char *data = chunk.ptr;
- size_t len = chunk.len;
- u_int32_t tmp;
- int rem;
+ u_int64_t v = 0;
+ int i;
- if (!len || data == NULL)
+ for (i = 0; i < 64; i += 8, ++in)
{
- return 0;
+ v |= ((u_int64_t)*in) << i;
}
+ return v;
+}
- rem = len & 3;
- len >>= 2;
+static inline u_int64_t siprotate(u_int64_t v, int shift)
+{
+ return (v << shift) | (v >> (64 - shift));
+}
- /* 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;
- }
+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;
+}
- /* Handle end cases */
+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:
- {
- hash += get16bits(data);
- hash ^= hash << 16;
- hash ^= data[sizeof(u_int16_t)] << 18;
- hash += hash >> 11;
- break;
- }
+ b |= ((u_int64_t)pos[2]) << 16;
case 2:
- {
- hash += get16bits(data);
- hash ^= hash << 11;
- hash += hash >> 17;
+ b |= ((u_int64_t)pos[1]) << 8;
+ case 1:
+ b |= ((u_int64_t)pos[0]);
+ break;
+ case 0:
break;
+ }
+ return b;
+}
+
+/**
+ * Caculate SipHash-2-4 with an optional first block given as argument.
+ */
+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;
+ 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;
+
+ if (m)
+ {
+ sipcompress(&v0, &v1, &v2, &v3, m);
+ }
+
+ /* 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.
+ */
+u_int64_t chunk_mac(chunk_t chunk, u_char *key)
+{
+ return chunk_mac_inc(chunk, key, 0);
+}
+
+/**
+ * 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;
}
- case 1:
+ 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++)
{
- hash += *data;
- hash ^= hash << 10;
- hash += hash >> 1;
- break;
+ key[done] = (u_char)random();
}
}
+}
- /* 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;
+/**
+ * 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);
}
/**
*/
u_int32_t chunk_hash(chunk_t chunk)
{
- return chunk_hash_inc(chunk, chunk.len);
+ pthread_once(&key_allocated, allocate_key);
+ return chunk_mac(chunk, key);
}
/**
/*
- * 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
#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
/**
* 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.
+ *
+ * @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);
+/**
+ * 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.
*
for (i = 0; i < count; i++)
{
- if (strcaseeq(name, e->names[i]))
+ if (name && strcaseeq(name, e->names[i]))
{
return e->first + i;
}
}
}
+/**
+ * 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
*/
{
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);
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)
{
switch (state)
{
case SEARCH_OID:
- if (*src != ' ' && *src != '/' && *src != ',')
+ if (*src != ' ' && *src != '/' && *src != ',' && *src != '\0')
{
oid.ptr = src;
oid.len = 1;
{
break;
}
- else if (*src != ',' && *src != '/')
+ else if (*src != ',' && *src != '/' && *src != '\0')
{
name.ptr = src;
name.len = 1;
}
} while (*src++ != '\0');
+ if (state == READ_OID)
+ { /* unterminated OID */
+ status = INVALID_ARG;
+ }
+
/* build the distinguished name sequence */
{
int i;
free(rdns[i].ptr);
}
}
-
if (status != SUCCESS)
{
free(dn->ptr);
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, '?') &&
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;
}
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, "::")
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;
}
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;
}
string += 1;
this->encoded.len = strlen(string);
if (this->encoded.len)
- {
+ { /* if we only got an @ */
this->encoded.ptr = strdup(string);
}
return &this->public;
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;
}
}
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);
{
if (lib->leak_detective)
{
- int leaks = 0, whitelisted = 0;
+ int leaks, whitelisted = 0;
leaks = print_traces(this, stderr, 0, detailed, &whitelisted);
switch (leaks)
}
}
+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)
{
INIT(this,
.public = {
.report = _report,
+ .leaks = _leaks,
.usage = _usage,
.set_state = _set_state,
.destroy = _destroy,
*/
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.
*
"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.
*/
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))
*/
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
*/
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++;