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:
@@ -34,3 +34,7 @@ apidoc/
|
||||
*.tar.bz2
|
||||
*.tar.gz
|
||||
.DS_Store
|
||||
coverage/
|
||||
*.gcno
|
||||
*.gcda
|
||||
*.gcov
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
test_runner
|
||||
@@ -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@
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
+37
-27
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user