Merge branch 'unit-tests'

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).
This commit is contained in:
Tobias Brunner
2013-06-11 11:16:30 +02:00
38 changed files with 5270 additions and 995 deletions
+4
View File
@@ -34,3 +34,7 @@ apidoc/
*.tar.bz2
*.tar.gz
.DS_Store
coverage/
*.gcno
*.gcda
*.gcov
+4 -1
View File
@@ -18,8 +18,11 @@ the code, you need the following tools:
- lex/flex
- yacc/bison
- gperf
Optionally:
- check
- optionally Doxygen
- lcov/genhtml
- Doxygen
To check out the master branch, use:
+34 -2
View File
@@ -37,5 +37,37 @@ Doxyfile : Doxyfile.in
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
+26
View File
@@ -243,6 +243,7 @@ ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that
ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
ARG_ENABL_SET([unwind-backtraces],[use libunwind to create backtraces for memory leaks and segfaults.])
ARG_ENABL_SET([unit-tests], [enable unit tests using the check test framework.])
ARG_ENABL_SET([coverage], [enable lcov coverage report generation.])
ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.])
ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.])
@@ -362,6 +363,10 @@ if test x$medcli = xtrue; then
mediation=true
fi
if test x$coverage = xtrue; then
unit_tests=true
fi
# ===========================================
# check required libraries and header files
# ===========================================
@@ -917,6 +922,25 @@ if test x$unit_tests = xtrue; then
AC_SUBST(CHECK_LIBS)
fi
if test x$coverage = xtrue; then
AC_PATH_PROG([LCOV], [lcov], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
if test x$LCOV = x; then
AC_MSG_ERROR([lcov not found])
fi
AC_PATH_PROG([GENHTML], [genhtml], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
if test x$GENHTML = x; then
AC_MSG_ERROR([genhtml not found])
fi
COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage"
COVERAGE_LDFLAGS="-fprofile-arcs"
AC_SUBST(COVERAGE_CFLAGS)
AC_SUBST(COVERAGE_LDFLAGS)
AC_MSG_NOTICE([coverage enabled, adding "-g -O0" to CFLAGS])
CFLAGS="${CFLAGS} -g -O0"
fi
# ===============================================
# collect plugin list for strongSwan components
# ===============================================
@@ -1241,6 +1265,7 @@ AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers)
AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes)
AM_CONDITIONAL(UNITTESTS, test x$unit_tests = xtrue)
AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue)
AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
@@ -1320,6 +1345,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/gcm/Makefile
src/libstrongswan/plugins/af_alg/Makefile
src/libstrongswan/plugins/test_vectors/Makefile
src/libstrongswan/tests/Makefile
src/libhydra/Makefile
src/libhydra/plugins/attr/Makefile
src/libhydra/plugins/attr_sql/Makefile
@@ -12,19 +12,14 @@ endif
libstrongswan_unit_tester_la_SOURCES = \
unit_tester.c unit_tester.h tests.h \
tests/test_enumerator.c \
tests/test_auth_info.c \
tests/test_curl.c \
tests/test_mysql.c \
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
-12
View File
@@ -18,27 +18,15 @@
* @{ @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)
/** @}*/
@@ -1,82 +0,0 @@
/*
* 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;
}
@@ -1,306 +0,0 @@
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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;
}
@@ -1,111 +0,0 @@
/*
* Copyright (C) 2010 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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;
}
@@ -1,249 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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, [email protected], CN=martin");
if (!test_id_equals_one(a, "C=CH, [email protected], CN=martin"))
{
return FALSE;
}
if (!test_id_equals_one(a, "C=ch, [email protected], CN=Martin"))
{
return FALSE;
}
if (test_id_equals_one(a, "C=CN, [email protected], CN=martin"))
{
return FALSE;
}
if (test_id_equals_one(a, "[email protected], C=CH, CN=martin"))
{
return FALSE;
}
if (test_id_equals_one(a, "[email protected], 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, [email protected], 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, [email protected], 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, [email protected], CN=martin");
if (test_id_matches_one(a, "C=CH, [email protected], 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=*, [email protected], CN=*") != ID_MATCH_NONE)
{
return FALSE;
}
a->destroy(a);
return TRUE;
}
+9 -1
View File
@@ -87,7 +87,8 @@ AM_CFLAGS = \
-DIPSEC_DIR=\"${ipsecdir}\" \
-DIPSEC_LIB_DIR=\"${ipseclibdir}\" \
-DPLUGINDIR=\"${plugindir}\" \
-DSTRONGSWAN_CONF=\"${strongswan_conf}\"
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
@COVERAGE_CFLAGS@
if USE_LEAK_DETECTIVE
AM_CFLAGS += -DLEAK_DETECTIVE
@@ -455,3 +456,10 @@ if MONOLITHIC
libstrongswan_la_LIBADD += plugins/test_vectors/libstrongswan-test-vectors.la
endif
endif
if UNITTESTS
if MONOLITHIC
SUBDIRS += .
endif
SUBDIRS += tests
endif
+29 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010 Martin Willi
@@ -47,21 +47,27 @@ struct private_bio_writer_t {
};
/**
* Increase buffer size
* Increase buffer size, if required
*/
static void increase(private_bio_writer_t *this)
static inline void increase(private_bio_writer_t *this, size_t required)
{
this->buf.len += this->increase;
this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
bool inc = FALSE;
while (this->used + required > this->buf.len)
{
this->buf.len += this->increase;
inc = TRUE;
}
if (inc)
{
this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
}
}
METHOD(bio_writer_t, write_uint8, void,
private_bio_writer_t *this, u_int8_t value)
{
if (this->used + 1 > this->buf.len)
{
increase(this);
}
increase(this, 1);
this->buf.ptr[this->used] = value;
this->used += 1;
}
@@ -69,10 +75,7 @@ METHOD(bio_writer_t, write_uint8, void,
METHOD(bio_writer_t, write_uint16, void,
private_bio_writer_t *this, u_int16_t value)
{
if (this->used + 2 > this->buf.len)
{
increase(this);
}
increase(this, 2);
htoun16(this->buf.ptr + this->used, value);
this->used += 2;
}
@@ -80,10 +83,7 @@ METHOD(bio_writer_t, write_uint16, void,
METHOD(bio_writer_t, write_uint24, void,
private_bio_writer_t *this, u_int32_t value)
{
if (this->used + 3 > this->buf.len)
{
increase(this);
}
increase(this, 3);
value = htonl(value);
memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3);
this->used += 3;
@@ -92,10 +92,7 @@ METHOD(bio_writer_t, write_uint24, void,
METHOD(bio_writer_t, write_uint32, void,
private_bio_writer_t *this, u_int32_t value)
{
if (this->used + 4 > this->buf.len)
{
increase(this);
}
increase(this, 4);
htoun32(this->buf.ptr + this->used, value);
this->used += 4;
}
@@ -103,10 +100,7 @@ METHOD(bio_writer_t, write_uint32, void,
METHOD(bio_writer_t, write_uint64, void,
private_bio_writer_t *this, u_int64_t value)
{
if (this->used + 8 > this->buf.len)
{
increase(this);
}
increase(this, 8);
htoun64(this->buf.ptr + this->used, value);
this->used += 8;
}
@@ -114,10 +108,7 @@ METHOD(bio_writer_t, write_uint64, void,
METHOD(bio_writer_t, write_data, void,
private_bio_writer_t *this, chunk_t value)
{
while (this->used + value.len > this->buf.len)
{
increase(this);
}
increase(this, value.len);
memcpy(this->buf.ptr + this->used, value.ptr, value.len);
this->used += value.len;
}
@@ -125,6 +116,7 @@ METHOD(bio_writer_t, write_data, void,
METHOD(bio_writer_t, write_data8, void,
private_bio_writer_t *this, chunk_t value)
{
increase(this, 1 + value.len);
write_uint8(this, value.len);
write_data(this, value);
}
@@ -132,6 +124,7 @@ METHOD(bio_writer_t, write_data8, void,
METHOD(bio_writer_t, write_data16, void,
private_bio_writer_t *this, chunk_t value)
{
increase(this, 2 + value.len);
write_uint16(this, value.len);
write_data(this, value);
}
@@ -139,6 +132,7 @@ METHOD(bio_writer_t, write_data16, void,
METHOD(bio_writer_t, write_data24, void,
private_bio_writer_t *this, chunk_t value)
{
increase(this, 3 + value.len);
write_uint24(this, value.len);
write_data(this, value);
}
@@ -146,6 +140,7 @@ METHOD(bio_writer_t, write_data24, void,
METHOD(bio_writer_t, write_data32, void,
private_bio_writer_t *this, chunk_t value)
{
increase(this, 4 + value.len);
write_uint32(this, value.len);
write_data(this, value);
}
@@ -153,10 +148,7 @@ METHOD(bio_writer_t, write_data32, void,
METHOD(bio_writer_t, wrap8, void,
private_bio_writer_t *this)
{
if (this->used + 1 > this->buf.len)
{
increase(this);
}
increase(this, 1);
memmove(this->buf.ptr + 1, this->buf.ptr, this->used);
this->buf.ptr[0] = this->used;
this->used += 1;
@@ -165,10 +157,7 @@ METHOD(bio_writer_t, wrap8, void,
METHOD(bio_writer_t, wrap16, void,
private_bio_writer_t *this)
{
if (this->used + 2 > this->buf.len)
{
increase(this);
}
increase(this, 2);
memmove(this->buf.ptr + 2, this->buf.ptr, this->used);
htoun16(this->buf.ptr, this->used);
this->used += 2;
@@ -179,10 +168,7 @@ METHOD(bio_writer_t, wrap24, void,
{
u_int32_t len;
if (this->used + 3 > this->buf.len)
{
increase(this);
}
increase(this, 3);
memmove(this->buf.ptr + 3, this->buf.ptr, this->used);
len = htonl(this->used);
@@ -193,10 +179,7 @@ METHOD(bio_writer_t, wrap24, void,
METHOD(bio_writer_t, wrap32, void,
private_bio_writer_t *this)
{
if (this->used + 4 > this->buf.len)
{
increase(this);
}
increase(this, 4);
memmove(this->buf.ptr + 4, this->buf.ptr, this->used);
htoun32(this->buf.ptr, this->used);
this->used += 4;
@@ -207,10 +190,7 @@ METHOD(bio_writer_t, skip, chunk_t,
{
chunk_t skipped;
while (this->used + len > this->buf.len)
{
increase(this);
}
increase(this, len);
skipped = chunk_create(this->buf.ptr + this->used, len);
this->used += len;
return skipped;
+2 -12
View File
@@ -264,7 +264,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token)
}
}
/* trim trailing characters/separators */
/* trim trailing characters */
pos--;
while (pos >= *token)
{
@@ -278,17 +278,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token)
}
trim++;
}
sep = this->sep;
while (*sep)
{
if (*sep == *pos)
{
*(pos--) = '\0';
break;
}
sep++;
}
if (!*trim && !*sep)
if (!*trim)
{
break;
}
+5 -2
View File
@@ -82,6 +82,7 @@ struct linked_list_t {
* current position.
*
* @param enumerator enumerator to check
* @return TRUE if more elements follow after the current item
*/
bool (*has_more)(linked_list_t *this, enumerator_t *enumerator);
@@ -180,7 +181,8 @@ struct linked_list_t {
*/
status_t (*get_last) (linked_list_t *this, void **item);
/** Find the first matching element in the list.
/**
* Find the first matching element in the list.
*
* The first object passed to the match function is the current list item,
* followed by the user supplied data.
@@ -200,7 +202,8 @@ struct linked_list_t {
status_t (*find_first) (linked_list_t *this, linked_list_match_t match,
void **item, ...);
/** Find the last matching element in the list.
/**
* Find the last matching element in the list.
*
* The first object passed to the match function is the current list item,
* followed by the user supplied data.
+1
View File
@@ -0,0 +1 @@
test_runner
+19
View File
@@ -0,0 +1,19 @@
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@
+450
View File
@@ -0,0 +1,450 @@
/*
* 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;
}
+386
View File
@@ -0,0 +1,386 @@
/*
* 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;
}
+824
View File
@@ -0,0 +1,824 @@
/*
* 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;
}
+248
View File
@@ -0,0 +1,248 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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;
}
+409
View File
@@ -0,0 +1,409 @@
/*
* 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;
}
+346
View File
@@ -0,0 +1,346 @@
/*
* 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;
}
@@ -0,0 +1,715 @@
/*
* 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("[email protected]");
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("[email protected]");
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 }},
{"[email protected]", 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("[email protected]", "[email protected]");
string_equals("[email protected]", "[email protected]");
/* non-printable characters */
string_equals_id("[email protected]", 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("[email protected]", identification_create_from_encoding(ID_KEY_ID,
chunk_from_str("[email protected]")));
/* 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, [email protected], CN=moon",
"C=CH, [email protected], CN=moon");
string_equals("C=CH, [email protected], CN=moon",
"C=CH, [email protected], 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)));
/* [email protected] 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("[email protected]");
snprintf(buf, sizeof(buf), "%25Y", a);
ck_assert_str_eq(" [email protected]", buf);
snprintf(buf, sizeof(buf), "%-*Y", 25, a);
ck_assert_str_eq("[email protected] ", buf);
snprintf(buf, sizeof(buf), "%5Y", a);
ck_assert_str_eq("[email protected]", 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, [email protected], CN=moon");
ck_assert(id_equals(a, "C=CH, [email protected], CN=moon"));
ck_assert(id_equals(a, "C==CH, [email protected],,, CN==moon"));
ck_assert(id_equals(a, " C=CH, [email protected], CN=moon "));
ck_assert(id_equals(a, "C=ch, [email protected], CN=Moon"));
ck_assert(id_equals(a, "/C=CH/[email protected]/CN=moon"));
ck_assert(id_equals(a, "C=CH/[email protected]/CN=moon"));
ck_assert(id_equals(a, "C=CH/[email protected],CN=moon"));
ck_assert(id_equals(a, "C=CH / [email protected] , CN=moon"));
ck_assert(!id_equals(a, "C=CH [email protected] CN=moon"));
ck_assert(!id_equals(a, "C=CN, [email protected], CN=moon"));
ck_assert(!id_equals(a, "[email protected], C=CH, CN=moon"));
ck_assert(!id_equals(a, "[email protected], 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, [email protected], CN=moon"))
{
printf("%d %B\n%B\n", i, &fuzzed, &encoding);
}
ck_assert(!id_equals(a, "C=CH, [email protected], 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, [email protected], 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, [email protected], CN=moon");
ck_assert(id_matches(a, "C=CH, [email protected], 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=*, [email protected], 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, "[email protected]", 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("[email protected]");
ck_assert(id_matches(a, "[email protected]", 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("[email protected]");
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;
}
+431
View File
@@ -0,0 +1,431 @@
/*
* 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;
}
@@ -0,0 +1,381 @@
/*
* 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;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* 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;
}
+33
View File
@@ -0,0 +1,33 @@
/*
* 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_ */
+101
View File
@@ -0,0 +1,101 @@
/*
* 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_ */
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -13,41 +14,44 @@
* for more details.
*/
#include <library.h>
#include <threading/mutex.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#include "test_suite.h"
#include <threading/mutex.h>
/*******************************************************************************
* recursive mutex test
*/
#define THREADS 20
static mutex_t *mutex;
static int locked = 0;
static pthread_barrier_t mutex_barrier;
static bool failed = FALSE;
static int mutex_locked = 0;
static pthread_barrier_t barrier;
static void* run(void* null)
static void *mutex_run(void *data)
{
int i;
/* wait for all threads before getting in action */
pthread_barrier_wait(&barrier);
pthread_barrier_wait(&mutex_barrier);
for (i = 0; i < 100; i++)
{
mutex->lock(mutex);
mutex->lock(mutex);
mutex->lock(mutex);
locked++;
mutex_locked++;
sched_yield();
if (locked > 1)
if (mutex_locked > 1)
{
failed = TRUE;
fail("two threads locked the mutex concurrently");
}
locked--;
mutex_locked--;
mutex->unlock(mutex);
mutex->unlock(mutex);
mutex->unlock(mutex);
@@ -55,15 +59,10 @@ static void* run(void* null)
return NULL;
}
#define THREADS 20
/*******************************************************************************
* mutex test
******************************************************************************/
bool test_mutex()
START_TEST(test_mutex)
{
int i;
pthread_t threads[THREADS];
int i;
mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
@@ -81,20 +80,31 @@ bool test_mutex()
mutex->unlock(mutex);
}
pthread_barrier_init(&barrier, NULL, THREADS);
pthread_barrier_init(&mutex_barrier, NULL, THREADS);
for (i = 0; i < THREADS; i++)
{
pthread_create(&threads[i], NULL, run, NULL);
pthread_create(&threads[i], NULL, mutex_run, NULL);
}
for (i = 0; i < THREADS; i++)
{
pthread_join(threads[i], NULL);
}
pthread_barrier_destroy(&barrier);
pthread_barrier_destroy(&mutex_barrier);
mutex->destroy(mutex);
return !failed;
}
END_TEST
Suite *threading_suite_create()
{
Suite *s;
TCase *tc;
s = suite_create("threading");
tc = tcase_create("recursive mutex");
tcase_add_test(tc, test_mutex);
suite_add_tcase(s, tc);
return s;
}
+432
View File
@@ -0,0 +1,432 @@
/*
* 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;
}
+183 -74
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -16,24 +16,17 @@
*/
#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.
*/
@@ -578,73 +571,188 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
return printable;
}
/**
* Helper functions for chunk_mac()
*/
static inline u_int64_t sipget(u_char *in)
{
u_int64_t v = 0;
int i;
for (i = 0; i < 64; i += 8, ++in)
{
v |= ((u_int64_t)*in) << i;
}
return v;
}
static inline u_int64_t siprotate(u_int64_t v, int shift)
{
return (v << shift) | (v >> (64 - shift));
}
static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
u_int64_t *v3)
{
*v0 += *v1;
*v1 = siprotate(*v1, 13);
*v1 ^= *v0;
*v0 = siprotate(*v0, 32);
*v2 += *v3;
*v3 = siprotate(*v3, 16);
*v3 ^= *v2;
*v2 += *v1;
*v1 = siprotate(*v1, 17);
*v1 ^= *v2;
*v2 = siprotate(*v2, 32);
*v0 += *v3;
*v3 = siprotate(*v3, 21);
*v3 ^= *v0;
}
static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
u_int64_t *v3, u_int64_t m)
{
*v3 ^= m;
sipround(v0, v1, v2, v3);
sipround(v0, v1, v2, v3);
*v0 ^= m;
}
static inline u_int64_t siplast(size_t len, u_char *pos)
{
u_int64_t b;
int rem = len & 7;
b = ((u_int64_t)len) << 56;
switch (rem)
{
case 7:
b |= ((u_int64_t)pos[6]) << 48;
case 6:
b |= ((u_int64_t)pos[5]) << 40;
case 5:
b |= ((u_int64_t)pos[4]) << 32;
case 4:
b |= ((u_int64_t)pos[3]) << 24;
case 3:
b |= ((u_int64_t)pos[2]) << 16;
case 2:
b |= ((u_int64_t)pos[1]) << 8;
case 1:
b |= ((u_int64_t)pos[0]);
break;
case 0:
break;
}
return b;
}
/**
* 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;
}
close(fd);
}
/* on error we use random() to generate the key (better than nothing) */
if (done < sizeof(key))
{
srandom(time(NULL) + getpid());
for (; done < sizeof(key); done++)
{
key[done] = (u_char)random();
}
}
}
/**
* Described in header.
*
* The implementation is based on Paul Hsieh's SuperFastHash:
* http://www.azillionmonkeys.com/qed/hash.html
*/
u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
{
u_char *data = chunk.ptr;
size_t len = chunk.len;
u_int32_t tmp;
int rem;
if (!len || data == NULL)
{
return 0;
}
rem = len & 3;
len >>= 2;
/* Main loop */
for (; len > 0; --len)
{
hash += get16bits(data);
tmp = (get16bits(data + 2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof(u_int16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem)
{
case 3:
{
hash += get16bits(data);
hash ^= hash << 16;
hash ^= data[sizeof(u_int16_t)] << 18;
hash += hash >> 11;
break;
}
case 2:
{
hash += get16bits(data);
hash ^= hash << 11;
hash += hash >> 17;
break;
}
case 1:
{
hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
break;
}
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
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);
}
/**
@@ -652,7 +760,8 @@ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
*/
u_int32_t chunk_hash(chunk_t chunk)
{
return chunk_hash_inc(chunk, chunk.len);
pthread_once(&key_allocated, allocate_key);
return chunk_mac(chunk, key);
}
/**
+26 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -191,9 +191,9 @@ static inline void chunk_clear(chunk_t *chunk)
#define chunk_from_thing(thing) chunk_create((char*)&(thing), sizeof(thing))
/**
* Initialize a chunk from a static string, not containing 0-terminator
* Initialize a chunk from a string, not containing 0-terminator
*/
#define chunk_from_str(str) chunk_create(str, strlen(str))
#define chunk_from_str(str) ({char *x = (str); chunk_create(x, strlen(x));})
/**
* Allocate a chunk on the heap
@@ -301,15 +301,37 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace);
/**
* Computes a 32 bit hash of the given chunk.
* Note: This hash is only intended for hash tables not for cryptographic purposes.
*
* @note This hash is only intended for hash tables not for cryptographic purposes.
*
* @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.
*
+1 -1
View File
@@ -47,7 +47,7 @@ int enum_from_name(enum_name_t *e, char *name)
for (i = 0; i < count; i++)
{
if (strcaseeq(name, e->names[i]))
if (name && strcaseeq(name, e->names[i]))
{
return e->first + i;
}
+48 -34
View File
@@ -276,6 +276,23 @@ METHOD(identification_t, create_part_enumerator, enumerator_t*,
}
}
/**
* Print a separator between two RDNs
*/
static inline bool print_separator(char **buf, size_t *len)
{
int written;
written = snprintf(*buf, *len, ", ");
if (written < 0 || written >= *len)
{
return FALSE;
}
*buf += written;
*len -= written;
return TRUE;
}
/**
* Print a DN with all its RDN in a buffer to present it to the user
*/
@@ -292,8 +309,14 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
{
empty = FALSE;
oid = asn1_known_oid(oid_data);
/* previous RDN was empty but it wasn't the last one */
if (finished && !print_separator(&buf, &len))
{
break;
}
finished = FALSE;
oid = asn1_known_oid(oid_data);
if (oid == OID_UNKNOWN)
{
written = snprintf(buf, len, "%#B=", &oid_data);
@@ -319,21 +342,19 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
buf += written;
len -= written;
if (data.ptr + data.len != dn.ptr + dn.len)
{
written = snprintf(buf, len, ", ");
if (written < 0 || written >= len)
{
break;
}
buf += written;
len -= written;
if (!data.ptr)
{ /* we can't calculate if we're finished, assume we are */
finished = TRUE;
}
else
else if (data.ptr + data.len == dn.ptr + dn.len)
{
finished = TRUE;
break;
}
else if (!print_separator(&buf, &len))
{
break;
}
}
if (empty)
{
@@ -377,7 +398,7 @@ static status_t atodn(char *src, chunk_t *dn)
switch (state)
{
case SEARCH_OID:
if (*src != ' ' && *src != '/' && *src != ',')
if (*src != ' ' && *src != '/' && *src != ',' && *src != '\0')
{
oid.ptr = src;
oid.len = 1;
@@ -418,7 +439,7 @@ static status_t atodn(char *src, chunk_t *dn)
{
break;
}
else if (*src != ',' && *src != '/')
else if (*src != ',' && *src != '/' && *src != '\0')
{
name.ptr = src;
name.len = 1;
@@ -481,6 +502,11 @@ static status_t atodn(char *src, chunk_t *dn)
}
} while (*src++ != '\0');
if (state == READ_OID)
{ /* unterminated OID */
status = INVALID_ARG;
}
/* build the distinguished name sequence */
{
int i;
@@ -493,7 +519,6 @@ static status_t atodn(char *src, chunk_t *dn)
free(rdns[i].ptr);
}
}
if (status != SUCCESS)
{
free(dn->ptr);
@@ -799,7 +824,7 @@ int identification_printf_hook(printf_hook_data_t *data,
dntoa(this->encoded, buf, sizeof(buf));
break;
case ID_DER_ASN1_GN:
snprintf(buf, sizeof(buf), "(ASN.1 general Name");
snprintf(buf, sizeof(buf), "(ASN.1 general name)");
break;
case ID_KEY_ID:
if (chunk_printable(this->encoded, NULL, '?') &&
@@ -915,14 +940,15 @@ identification_t *identification_create_from_string(char *string)
else
{
this = identification_create(ID_KEY_ID);
this->encoded = chunk_clone(chunk_create(string, strlen(string)));
this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
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, "::")
@@ -947,11 +973,7 @@ identification_t *identification_create_from_string(char *string)
else
{ /* not IPv4, mostly FQDN */
this = identification_create(ID_FQDN);
this->encoded.len = strlen(string);
if (this->encoded.len)
{
this->encoded.ptr = strdup(string);
}
this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
@@ -968,11 +990,7 @@ identification_t *identification_create_from_string(char *string)
else
{ /* not IPv4/6 fallback to KEY_ID */
this = identification_create(ID_KEY_ID);
this->encoded.len = strlen(string);
if (this->encoded.len)
{
this->encoded.ptr = strdup(string);
}
this->encoded = chunk_from_str(strdup(string));
}
return &this->public;
}
@@ -996,7 +1014,7 @@ identification_t *identification_create_from_string(char *string)
string += 1;
this->encoded.len = strlen(string);
if (this->encoded.len)
{
{ /* if we only got an @ */
this->encoded.ptr = strdup(string);
}
return &this->public;
@@ -1005,11 +1023,7 @@ identification_t *identification_create_from_string(char *string)
else
{
this = identification_create(ID_RFC822_ADDR);
this->encoded.len = strlen(string);
if (this->encoded.len)
{
this->encoded.ptr = strdup(string);
}
this->encoded = chunk_from_str(strdup(string));
return &this->public;
}
}
+16 -2
View File
@@ -589,7 +589,7 @@ static int print_traces(private_leak_detective_t *this,
enumerator = entries->create_enumerator(entries);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
if (!thresh || entry->bytes >= thresh)
if (out && (!thresh || entry->bytes >= thresh))
{
fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
entry->bytes, entry->count, entry->bytes / entry->count);
@@ -609,7 +609,7 @@ METHOD(leak_detective_t, report, void,
{
if (lib->leak_detective)
{
int leaks = 0, whitelisted = 0;
int leaks, whitelisted = 0;
leaks = print_traces(this, stderr, 0, detailed, &whitelisted);
switch (leaks)
@@ -632,6 +632,19 @@ METHOD(leak_detective_t, report, void,
}
}
METHOD(leak_detective_t, leaks, int,
private_leak_detective_t *this)
{
if (lib->leak_detective)
{
int leaks, whitelisted = 0;
leaks = print_traces(this, NULL, 0, FALSE, &whitelisted);
return leaks;
}
return 0;
}
METHOD(leak_detective_t, set_state, bool,
private_leak_detective_t *this, bool enable)
{
@@ -885,6 +898,7 @@ leak_detective_t *leak_detective_create()
INIT(this,
.public = {
.report = _report,
.leaks = _leaks,
.usage = _usage,
.set_state = _set_state,
.destroy = _destroy,
+7
View File
@@ -42,6 +42,13 @@ struct leak_detective_t {
*/
void (*report)(leak_detective_t *this, bool detailed);
/**
* Number of detected leaks.
*
* @return number of leaks
*/
int (*leaks)(leak_detective_t *this);
/**
* Report current memory usage to out.
*
+6 -14
View File
@@ -45,19 +45,6 @@ ENUM(status_names, SUCCESS, NEED_MORE,
"NEED_MORE",
);
/**
* Described in header.
*/
void *clalloc(void * pointer, size_t size)
{
void *data;
data = malloc(size);
memcpy(data, pointer, size);
return (data);
}
/**
* Described in header.
*/
@@ -115,7 +102,12 @@ void memwipe_noinline(void *ptr, size_t n)
void *memstr(const void *haystack, const char *needle, size_t n)
{
unsigned const char *pos = haystack;
size_t l = strlen(needle);
size_t l;
if (!haystack || !needle || (l = strlen(needle)) == 0)
{
return NULL;
}
for (; n >= l; ++pos, --n)
{
if (memeq(pos, needle, l))
+1 -6
View File
@@ -375,11 +375,6 @@ typedef struct timespec timespec_t;
*/
typedef struct sockaddr sockaddr_t;
/**
* Clone a data to a newly allocated buffer
*/
void *clalloc(void *pointer, size_t size);
/**
* Same as memcpy, but XORs src into dst instead of copy
*/
@@ -507,7 +502,7 @@ time_t time_monotonic(timeval_t *tv);
static inline void timeval_add_ms(timeval_t *tv, u_int ms)
{
tv->tv_usec += ms * 1000;
while (tv->tv_usec > 1000000 /* 1s */)
while (tv->tv_usec >= 1000000 /* 1s */)
{
tv->tv_usec -= 1000000;
tv->tv_sec++;