summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-09 16:36:34 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-09 16:36:34 +0100
commit9b0a0ba9e671d9134b93c33ab73ccccb352acafa (patch)
tree2a3b007b698c02c72c7bae25d3c7cae6293cd36f
parent8860e991f6650e47cfe6c1af595fe4fe92a4edfd (diff)
Unit Testing for BIRD
- Unit Testing Framework (BirdTest) - Integration of BirdTest into the BIRD build system - Tests for several BIRD modules Based on squashed Pavel Tvrdik's int-test branch, updated for current int-new branch.
-rw-r--r--Makefile.in33
-rw-r--r--conf/Makefile2
-rw-r--r--conf/conf.c7
-rw-r--r--conf/conf.h6
-rw-r--r--configure.in5
-rw-r--r--doc/bird.sgml2
-rw-r--r--filter/Makefile4
-rw-r--r--filter/config.Y98
-rw-r--r--filter/filter.c17
-rw-r--r--filter/filter.h21
-rw-r--r--filter/filter_test.c87
-rw-r--r--filter/test.conf1139
-rw-r--r--filter/test.conf.inc1
-rw-r--r--filter/test.conf294
-rw-r--r--filter/test6.conf17
-rw-r--r--filter/test_bgp_filtering.conf113
-rw-r--r--filter/tree_test.c304
-rw-r--r--filter/trie_test.c184
-rw-r--r--lib/Makefile4
-rw-r--r--lib/birdlib.h3
-rw-r--r--lib/bitops.h2
-rw-r--r--lib/bitops_test.c123
-rw-r--r--lib/buffer_test.c147
-rw-r--r--lib/checksum_test.c94
-rw-r--r--lib/event_test.c88
-rw-r--r--lib/fletcher16_test.c169
-rw-r--r--lib/hash_test.c305
-rw-r--r--lib/heap_test.c186
-rw-r--r--lib/ip.c2
-rw-r--r--lib/ip_test.c161
-rw-r--r--lib/lists_test.c287
-rw-r--r--lib/mac_test.c1159
-rw-r--r--lib/patmatch_test.c149
-rw-r--r--lib/printf_test.c70
-rw-r--r--lib/slist_test.c384
-rw-r--r--lib/slists.c82
-rw-r--r--nest/Makefile4
-rw-r--r--nest/a-path.c3
-rw-r--r--nest/a-path_test.c214
-rw-r--r--nest/a-set_test.c260
-rw-r--r--nest/iface.h1
-rw-r--r--nest/route.h2
-rw-r--r--proto/bfd/Makefile2
-rw-r--r--proto/bgp/Makefile2
-rw-r--r--proto/ospf/Makefile2
-rw-r--r--proto/ospf/rt.c2
-rw-r--r--proto/pipe/Makefile2
-rw-r--r--proto/radv/Makefile2
-rw-r--r--proto/radv/radv.c2
-rw-r--r--proto/rip/Makefile2
-rw-r--r--proto/static/Makefile2
-rw-r--r--sysdep/autoconf.h.in3
-rw-r--r--sysdep/bsd/Makefile1
-rw-r--r--sysdep/linux/Makefile2
-rw-r--r--sysdep/unix/Makefile3
-rw-r--r--test/Makefile3
-rw-r--r--test/birdtest.c488
-rw-r--r--test/birdtest.h183
-rw-r--r--test/bt-utils.c223
-rw-r--r--test/bt-utils.h35
60 files changed, 6504 insertions, 488 deletions
diff --git a/Makefile.in b/Makefile.in
index cee217be..63d3351f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -22,7 +22,7 @@ INSTALL_DATA=@INSTALL_DATA@
client=$(addprefix $(exedir)/,@CLIENT@)
daemon=$(exedir)/bird
-protocols = @protocols@
+protocols=@protocols@
prefix=@prefix@
exec_prefix=@exec_prefix@
@@ -49,24 +49,26 @@ else
endif
# Meta rules
-cleangoals := clean distclean
docgoals := docs userdocs progdocs
-.PHONY: all daemon cli $(cleangoals) $(docgoals) tags
+testgoals := check test tests tests_run
+cleangoals := clean distclean testsclean
+.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags
all: daemon cli
daemon: $(daemon)
cli: $(client)
# Include directories
-dirs := client conf doc filter lib nest $(addprefix proto/,$(protocols)) @sysdep_dirs@
+dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@
conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h)
cf-local = $(conf-y-targets): $(s)config.Y
src-o-files = $(patsubst %.c,$(o)%.o,$(src))
+tests-target-files = $(patsubst %.c,$(o)%,$(tests_src))
-all-daemon = $(exedir)/bird: $(obj)
-all-client = $(exedir)/birdc $(exedir)/birdcl: $(obj)
+all-daemon = $(daemon): $(obj)
+all-client = $(client): $(obj)
s = $(dir $(lastword $(MAKEFILE_LIST)))
ifeq ($(srcdir),.)
@@ -109,6 +111,22 @@ $(objdir)/sysdep/paths.h: Makefile
echo >>$@ "#define PATH_CONTROL_SOCKET \"@CONTROL_SOCKET@\""
if test -n "@iproutedir@" ; then echo >>$@ "#define PATH_IPROUTE_DIR \"@iproutedir@\"" ; fi
+# Unit tests rules
+
+tests_targets_ok = $(addsuffix .ok,$(tests_targets))
+
+$(tests_targets): %: %.o $(tests_objs)
+ $(E)echo LD $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+$(tests_targets_ok): %.ok: %
+ $(Q)$* 2>/dev/null && touch $*.ok
+
+test: testsclean check
+check: tests tests_run
+tests: $(tests_targets)
+tests_run: $(tests_targets_ok)
+
# Finally include the computed dependencies
ifneq ($(filter-out $(cleangoals),$(MAKECMDGOALS)),)
@@ -147,6 +165,9 @@ clean::
rm -f $(addprefix $(exedir)/,bird birdc birdcl)
find $(objdir) -name "*.[od]" -exec rm -f '{}' '+'
+testsclean:
+ rm -f $(tests_targets_ok)
+
ifeq ($(objdir),obj)
distclean: clean
rm -rf $(objdir)
diff --git a/conf/Makefile b/conf/Makefile
index e5828538..cc2b13c6 100644
--- a/conf/Makefile
+++ b/conf/Makefile
@@ -3,6 +3,8 @@ obj := $(src-o-files)
$(all-daemon)
+tests_objs := $(tests_objs) $(src-o-files)
+
ifdef DEBUG
BISON_DEBUG=-t
#FLEX_DEBUG=-d
diff --git a/conf/conf.c b/conf/conf.c
index b6f41b2c..3ae85cb2 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -49,12 +49,10 @@
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
-#include "lib/resource.h"
-#include "lib/string.h"
#include "lib/event.h"
#include "sysdep/unix/timer.h"
#include "conf/conf.h"
-#include "filter/filter.h"
+
static jmp_buf conf_jmpbuf;
@@ -85,7 +83,7 @@ int undo_available; /* Undo was not requested from last reconfiguration */
* further use. Returns a pointer to the structure.
*/
struct config *
-config_alloc(const byte *name)
+config_alloc(const char *name)
{
pool *p = rp_new(&root_pool, "Config");
linpool *l = lp_new(p, 4080);
@@ -96,6 +94,7 @@ config_alloc(const byte *name)
char *ndup = lp_allocu(l, nlen);
memcpy(ndup, name, nlen);
+ init_list(&c->tests);
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
c->pool = p;
c->mem = l;
diff --git a/conf/conf.h b/conf/conf.h
index 593a5f13..cb5ade47 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -9,6 +9,8 @@
#ifndef _BIRD_CONF_H_
#define _BIRD_CONF_H_
+#include "sysdep/config.h"
+#include "lib/ip.h"
#include "lib/resource.h"
#include "sysdep/unix/timer.h"
@@ -21,6 +23,7 @@ struct config {
list protos; /* Configured protocol instances (struct proto_config) */
list tables; /* Configured routing tables (struct rtable_config) */
list logfiles; /* Configured log files (sysdep) */
+ list tests; /* Configured unit tests */
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
@@ -60,7 +63,7 @@ struct config {
extern struct config *config; /* Currently active configuration */
extern struct config *new_config; /* Configuration being parsed */
-struct config *config_alloc(const byte *name);
+struct config *config_alloc(const char *name);
int config_parse(struct config *);
int cli_parse(struct config *);
void config_free(struct config *);
@@ -161,6 +164,7 @@ static inline int cf_symbol_is_constant(struct symbol *sym)
/* Parser */
+extern char *cf_text;
int cf_parse(void);
/* Sysdep hooks */
diff --git a/configure.in b/configure.in
index 58f865c4..912598b8 100644
--- a/configure.in
+++ b/configure.in
@@ -56,7 +56,7 @@ if test "$ac_test_CFLAGS" != set ; then
bird_cflags_default=yes
fi
-AC_PROG_CC
+AC_PROG_CC_C99
if test -z "$GCC" ; then
AC_MSG_ERROR([This program requires the GNU C Compiler.])
fi
@@ -220,6 +220,9 @@ BIRD_CHECK_STRUCT_IP_MREQN
if test "$enable_debug" = yes ; then
AC_DEFINE(DEBUGGING)
+ AC_CHECK_HEADER(execinfo.h, [AC_SEARCH_LIBS([backtrace, backtrace_symbols], [c execinfo], [AC_DEFINE(HAVE_EXECINFO_H)])])
+ LDFLAGS="$LDFLAGS -rdynamic"
+ CFLAGS="$CFLAGS -O0 -ggdb -g3 -gdwarf-4"
if test "$enable_memcheck" = yes ; then
AC_CHECK_LIB(dmalloc, dmalloc_debug)
if test $ac_cv_lib_dmalloc_dmalloc_debug != yes ; then
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 6af0e0f6..e70232d1 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1253,7 +1253,7 @@ foot).
<cf/!&tilde;/ membership operators) can be used to modify or test
eclists, with ECs instead of pairs as arguments.
- <tag/lclist/
+ <tag><label id="type-lclist">lclist/</tag>
Lclist is a data type used for BGP large community lists. Like eclists,
lclists are very similar to clists, but they are sets of LCs instead of
pairs. The same operations (like <cf/add/, <cf/delete/ or <cf/&tilde;/
diff --git a/filter/Makefile b/filter/Makefile
index f27befdf..6bada8ca 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -2,3 +2,7 @@ src := filter.c f-util.c tree.c trie.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_src := tree_test.c filter_test.c trie_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/filter/config.Y b/filter/config.Y
index 8af444a3..b5ae850a 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -323,7 +323,71 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
return rv;
}
+/*
+ * Remove all new lines and doubled whitespaces
+ * and convert all tabulators to spaces
+ * and return a copy of string
+ */
+char *
+assert_copy_expr(const char *start, size_t len)
+{
+ /* XXX: Allocates maybe a little more memory than we really finally need */
+ char *str = cfg_alloc(len + 1);
+
+ char *dst = str;
+ const char *src = start - 1;
+ const char *end = start + len;
+ while (++src < end)
+ {
+ if (*src == '\n')
+ continue;
+
+ /* Skip doubled whitespaces */
+ if (src != start)
+ {
+ const char *prev = src - 1;
+ if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
+ continue;
+ }
+
+ if (*src == '\t')
+ *dst = ' ';
+ else
+ *dst = *src;
+
+ dst++;
+ }
+ *dst = '\0';
+
+ return str;
+}
+
+/*
+ * assert_done - create f_instruction of bt_assert
+ * @expr: expression in bt_assert()
+ * @start: pointer to first char of test expression
+ * @end: pointer to the last char of test expression
+ */
+static struct f_inst *
+assert_done(struct f_inst *expr, const char *start, const char *end)
+{
+ struct f_inst *i;
+ i = f_new_inst();
+ i->code = P('a','s');
+ i->a1.p = expr;
+
+ if (end >= start)
+ {
+ i->a2.p = assert_copy_expr(start, end - start + 1);
+ }
+ else
+ {
+ /* this is a break of lexer buffer */
+ i->a2.p = "???";
+ }
+ return i;
+}
CF_DECLS
@@ -341,12 +405,13 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
EMPTY,
- FILTER, WHERE, EVAL)
+ FILTER, WHERE, EVAL,
+ BT_ASSERT, BT_TEST_SUITE)
%nonassoc THEN
%nonassoc ELSE
-%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
+%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr bt_assert
%type <f> filter filter_body where_filter
%type <i> type break_command ec_kind
%type <i32> cnum
@@ -356,6 +421,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <px> fprefix
%type <s> decls declsn one_decl function_params
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
+%type <t> get_cf_position
CF_GRAMMAR
@@ -375,6 +441,21 @@ filter_eval:
EVAL term { f_eval_int($2); }
;
+CF_ADDTO(conf, bt_test_suite)
+bt_test_suite:
+ BT_TEST_SUITE '(' SYM ',' text ')' {
+ if (!($3->class & SYM_FUNCTION))
+ cf_error("Function expected");
+
+ struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
+ t->fn = $3->def;
+ t->fn_name = $3->name;
+ t->dsc = $5;
+
+ add_tail(&new_config->tests, &t->n);
+ }
+ ;
+
type:
INT { $$ = T_INT; }
| BOOL { $$ = T_BOOL; }
@@ -835,6 +916,8 @@ term:
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+ | bt_assert { $$ = $1; }
+
/* | term '.' LEN { $$->code = P('P','l'); } */
/* function_call is inlined here */
@@ -966,6 +1049,7 @@ cmd:
$$->a1.p = $2;
$$->a2.p = build_tree( $4 );
}
+ | bt_assert ';' { $$ = $1; }
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
@@ -975,4 +1059,14 @@ cmd:
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
;
+ bt_assert:
+ BT_ASSERT '(' get_cf_position term get_cf_position ')' { $$ = assert_done($4, $3 + 1, $5 - 1); }
+ ;
+
+get_cf_position:
+{
+ $$ = cf_text;
+};
+
+
CF_END
diff --git a/filter/filter.c b/filter/filter.c
index 09b89401..3df602a3 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -52,6 +52,8 @@
#define CMP_ERROR 999
+void (*bt_assert_hook)(int result, struct f_inst *assert);
+
static struct adata *
adata_empty(struct linpool *pool, int l)
{
@@ -563,8 +565,8 @@ f_rta_cow(void)
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
-#define runtime(x) do { \
- log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
+#define runtime(fmt, ...) do { \
+ log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
res.type = T_RETURN; \
res.val.i = F_ERROR; \
return res; \
@@ -1475,6 +1477,17 @@ interpret(struct f_inst *what)
break;
+ case P('a', 's'): /* Birdtest Assert */
+ ONEARG;
+
+ if (v1.type != T_BOOL)
+ runtime("Should be boolean value");
+
+ res.type = v1.type;
+ res.val = v1.val;
+
+ CALL(bt_assert_hook, res.val.i, what);
+ break;
default:
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
diff --git a/filter/filter.h b/filter/filter.h
index fc11b91e..a4808731 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -16,16 +16,16 @@
struct f_inst { /* Instruction */
struct f_inst *next; /* Structure is 16 bytes, anyway */
- u16 code;
- u16 aux;
+ u16 code; /* Instruction code, see the interpret() function and P() macro */
+ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union {
int i;
void *p;
- } a1;
+ } a1; /* The first argument */
union {
int i;
void *p;
- } a2;
+ } a2; /* The second argument */
int lineno;
};
@@ -55,7 +55,7 @@ struct f_prefix {
};
struct f_val {
- int type;
+ int type; /* T_* */
union {
uint i;
u64 ec;
@@ -205,4 +205,15 @@ struct f_trie
#define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */
+/* Bird Tests */
+struct f_bt_test_suite {
+ node n; /* Node in config->tests */
+ struct f_inst *fn; /* Root of function */
+ const char *fn_name; /* Name of test */
+ const char *dsc; /* Description */
+};
+
+/* Hook for call bt_assert() function in configuration */
+extern void (*bt_assert_hook)(int result, struct f_inst *assert);
+
#endif
diff --git a/filter/filter_test.c b/filter/filter_test.c
new file mode 100644
index 00000000..693b1fe0
--- /dev/null
+++ b/filter/filter_test.c
@@ -0,0 +1,87 @@
+/*
+ * Filters: Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "filter/filter.h"
+#include "conf/conf.h"
+
+#define BT_CONFIG_FILE "filter/test.conf"
+
+
+static struct config *
+parse_config_file(const void *filename_void)
+{
+ bt_bird_init();
+
+ size_t fn_size = strlen((const char *) filename_void) + 1;
+ char *filename = alloca(fn_size);
+ strncpy(filename, filename_void, fn_size);
+
+ struct config *c = bt_config_file_parse(filename);
+ bt_bird_cleanup();
+
+ return c;
+}
+
+static int
+run_function(const void *parsed_fn_def)
+{
+ /* XXX: const -> non-const */
+ struct f_inst *f = (struct f_inst *) parsed_fn_def;
+
+ linpool *tmp = lp_new(&root_pool, 4096);
+ struct f_val res = f_eval(f, tmp);
+ rfree(tmp);
+
+ if (res.type == T_RETURN && res.val.i >= F_REJECT)
+ return BT_FAILURE;
+
+ return BT_SUCCESS;
+}
+
+static void
+bt_assert_filter(int result, struct f_inst *assert)
+{
+ int bt_suit_case_result = BT_SUCCESS;
+ if (!result)
+ {
+ bt_result = BT_FAILURE;
+ bt_suite_result = BT_FAILURE;
+ bt_suit_case_result = BT_FAILURE;
+ }
+
+ bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a2.p);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ struct config *c = parse_config_file(BT_CONFIG_FILE);
+
+ if (c)
+ {
+ bt_assert_hook = bt_assert_filter;
+
+ struct f_bt_test_suite *t;
+ WALK_LIST(t, c->tests)
+ bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
+ }
+
+ return bt_exit_value();
+}
diff --git a/filter/test.conf b/filter/test.conf
index e65b3ebb..de3a3113 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -1,24 +1,24 @@
-
/*
- * This is an example configuration file.
+ * This is unit testing configuration file for testing filters
+ *
* FIXME: add all examples from docs here.
*/
-# Yet another comment
-
router id 62.168.0.1;
-define xyzzy = (120+10);
-define '1a-a1' = (20+10);
-define one = 1;
-define ten = 10;
+/* We have to setup any protocol */
+protocol static { ipv4; }
+
-define p23 = (2, 3);
-define ip1222 = 1.2.2.2;
-define net10 = 10.0.0.0/8;
-define netdoc = 2001:db8::/32;
+/*
+ * Common definitions and functions
+ * --------------------------------
+ */
+
+define one = 1;
+define ten = 10;
function onef(int a)
{
@@ -26,108 +26,78 @@ function onef(int a)
}
-function 'mkpair-a'(int a)
-{
- return (1, a);
-}
-function mktrip(int a)
-{
- return (a, 2*a, 3*a);
-}
-function mkpath(int a; int b)
-{
- return [= a b 3 2 1 =];
-}
+/*
+ * Testing empty lists/paths
+ * -------------------------
+ */
-function callme(int arg1; int arg2)
-int local1;
-int local2;
-int i;
+function t_empty()
{
- printn "Function callme called arguments ", arg1, " and ", arg2, ": " ;
- i = arg2;
+ bt_assert(+empty+ = +empty+);
+ bt_assert(+empty+ != -empty-);
+ bt_assert(+empty+ != --empty--);
- case arg1 {
- 11, 1, 111: printn "jedna, "; printn "jedna";
- (one+onef(2)): printn "dva, "; printn "jeste jednou dva";
- (2+one) .. 5: if arg2 < 3 then printn "tri az pet";
- else: printn "neco jineho";
- }
- print;
-}
+ bt_assert(-empty- = -empty-);
+ bt_assert(-empty- != --empty--);
-function fifteen()
-{
- print "fifteen called";
- return 15;
+ bt_assert(--empty-- = --empty--);
}
+bt_test_suite(t_empty, "Testing +empty+, -empty-, --empty--");
+
+
+
+
/*
-roa table rl
-{
- roa 10.110.0.0/16 max 16 as 1000;
- roa 10.120.0.0/16 max 24 as 1000;
- roa 10.130.0.0/16 max 24 as 2000;
- roa 10.130.128.0/18 max 24 as 3000;
-}
+ * Testing Paths
+ * -------------
+ */
-function test_roa()
+function mkpath(int a; int b)
{
- # cannot be tested in __startup(), sorry
- print "Testing ROA";
- print "Should be true: ", roa_check(rl, 10.10.0.0/16, 1000) = ROA_UNKNOWN,
- " ", roa_check(rl, 10.0.0.0/8, 1000) = ROA_UNKNOWN,
- " ", roa_check(rl, 10.110.0.0/16, 1000) = ROA_VALID,
- " ", roa_check(rl, 10.110.0.0/16, 2000) = ROA_INVALID,
- " ", roa_check(rl, 10.110.32.0/20, 1000) = ROA_INVALID,
- " ", roa_check(rl, 10.120.32.0/20, 1000) = ROA_VALID;
- print "Should be true: ", roa_check(rl, 10.120.32.0/20, 2000) = ROA_INVALID,
- " ", roa_check(rl, 10.120.32.32/28, 1000) = ROA_INVALID,
- " ", roa_check(rl, 10.130.130.0/24, 1000) = ROA_INVALID,
- " ", roa_check(rl, 10.130.130.0/24, 2000) = ROA_VALID,
- " ", roa_check(rl, 10.130.30.0/24, 3000) = ROA_INVALID,
- " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID;
+ return [= a b 3 2 1 =];
}
-*/
-function path_test()
+function t_path()
bgpmask pm1;
bgpmask pm2;
bgppath p2;
-clist l;
-clist l2;
-eclist el;
-eclist el2;
-lclist ll;
-lclist ll2;
{
- print "Entering path test...";
pm1 = / 4 3 2 1 /;
- pm2 = [= 3..6 3 2 1..2 =];
- print "Testing path masks: ", pm1, " ", pm2;
+ pm2 = [= 4 3 2 1 =];
+
p2 = prepend( + empty +, 1 );
p2 = prepend( p2, 2 );
p2 = prepend( p2, 3 );
p2 = prepend( p2, 4 );
- print "Testing path: (4 3 2 1) = ", p2;
- print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20];
- print "4 = ", p2.len;
- p2 = prepend( p2, 5 );
- print "Testing path: (5 4 3 2 1) = ", p2;
- print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, ten..(2*ten)], " ", p2 ~ [= 1..4 4 3 2 1 =], " ", p2 ~ [= 5 4 4..100 2 1 =];
- print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /;
- print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =];
- print "Should be true: ", p2 ~ [= 5..6 4..10 1..3 1..3 1..65536 =];
- print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4);
- print "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1;
- print "Should be true: ", pm1 = [= 4 3 2 1 =], " ", pm1 != [= 4 3 1 2 =], " ",
- pm2 = [= 3..6 3 2 1..2 =], " ", pm2 != [= 3..6 3 2 1..3 =], " ",
- [= 1 2 (1+2) =] = [= 1 2 (1+2) =], " ", [= 1 2 (1+2) =] != [= 1 2 (2+1) =];
- print "5 = ", p2.len;
- print "Delete 3: ", delete(p2, 3);
- print "Filter 1-3: ", filter(p2, [1..3]);
+
+ print "Testing paths: ", p2;
+ bt_assert(p2.len = 4);
+ bt_assert(p2 ~ pm1);
+ bt_assert(p2 ~ pm2);
+ bt_assert(3 ~ p2);
+ bt_assert(p2 ~ [2, 10..20]);
+ bt_assert(p2 ~ [4, 10..20]);
+
+ p2 = prepend(p2, 5);
+ bt_assert(p2 !~ pm1);
+ bt_assert(p2 !~ pm2);
+ bt_assert(10 !~ p2);
+ bt_assert(p2 !~ [8, ten..(2*ten)]);
+ bt_assert(p2 ~ / ? 4 3 2 1 /);
+ bt_assert(p2 ~ [= * 4 3 * 1 =]);
+ bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]);
+ bt_assert(p2 ~ mkpath(5, 4));
+
+ bt_assert(p2.len = 5);
+ bt_assert(p2.first = 5);
+ bt_assert(p2.last = 1);
+
+ bt_assert(p2.len = 5);
+ bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 1), 2), 4), 5));
+ bt_assert(filter(p2, [1..3]) = prepend(prepend(prepend(+empty+, 1), 2), 3));
pm1 = [= 1 2 * 3 4 5 =];
p2 = prepend( + empty +, 5 );
@@ -136,63 +106,134 @@ lclist ll2;
p2 = prepend( p2, 3 );
p2 = prepend( p2, 2 );
p2 = prepend( p2, 1 );
- print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1;
- print "Delete 3: ", delete(p2, 3);
- print "Delete 4-5: ", delete(p2, [4..5]);
+
+ bt_assert(p2 ~ pm1);
+ bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 5), 4), 2), 1));
+ bt_assert(delete(p2, [4..5]) = prepend(prepend(prepend(prepend(+empty+, 3), 3), 2), 1));
+}
+
+bt_test_suite(t_path, "Testing paths");
+
+
+
+
+/*
+ * Testing Community List
+ * ----------------------
+ */
+
+define p23 = (2, 3);
+
+function t_community_list()
+clist l;
+clist l2;
+{
+ /* XXX: add((x,y)) works as prepend */
l = - empty -;
- print "Should be false in this special case: ", l ~ [(*,*)];
+ bt_assert(l !~ [(*,*)]);
+ bt_assert((l ~ [(*,*)]) != (l !~ [(*,*)]));
+
l = add( l, (one,2) );
- print "Should be always true: ", l ~ [(*,*)];
+ bt_assert(l ~ [(*,*)]);
l = add( l, (2,one+2) );
print "Community list (1,2) (2,3) ", l;
- print "Should be true: ", (2,3) ~ l, " ", l ~ [(1,*)], " ", l ~ [p23]," ", l ~ [(2,2..3)], " ", l ~ [(1,1..2)], " ", l ~ [(1,1)..(1,2)];
- l = add( l, (2,5) );
- l = add( l, (5,one) );
- l = add( l, (6,one) );
- l = add( l, (one,one) );
- l = delete( l, [(5,1),(6,one),(one,1)] );
- l = delete( l, [(5,one),(6,one)] );
- l = filter( l, [(1,*)] );
- print "Community list (1,2) ", l;
- print "Should be false: ", (2,3) ~ l, " ", l ~ [(2,*)], " ", l ~ [(one,3..6)];
- print "Should be always true: ", l ~ [(*,*)];
- l = add( l, (3,one) );
- l = add( l, (one+one+one,one+one) );
- l = add( l, (3,3) );
- l = add( l, (3,4) );
- l = add( l, (3,5) );
- l2 = filter( l, [(3,*)] );
- l = delete( l, [(3,2..4)] );
- print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len;
- l = add( l, (3,2) );
- l = add( l, (4,5) );
- print "Community list (1,2) (3,1) (3,5) (3,2) (4,5) ", l, " len: ", l.len;
- print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)];
- print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))];
- l = delete( l, [(*,(one+onef(3)))] );
- l = delete( l, [(*,(4+one))] );
- print "Community list (3,1) ", l;
- l = delete( l, [(*,(onef(5)))] );
- print "Community list empty ", l;
- l2 = add( l2, (3,6) );
- l = filter( l2, [(3,1..4)] );
- l2 = filter( l2, [(3,3..6)] );
+
+ bt_assert((2,3) ~ l);
+ bt_assert(l ~ [(1,*)]);
+ bt_assert(l ~ [p23]);
+ bt_assert(l ~ [(2,2..3)]);
+ bt_assert(l ~ [(1,1..2)]);
+ bt_assert(l ~ [(1,1)..(1,2)]);
+
+ l = add(l, (2,5));
+ l = add(l, (5,one));
+ l = add(l, (6,one));
+ l = add(l, (one,one));
+ l = delete(l, [(5,1),(6,one),(one,1)]);
+ l = delete(l, [(5,one),(6,one)]);
+ l = filter(l, [(1,*)]);
+ bt_assert(l = add(-empty-, (1,2)));
+
+ bt_assert((2,3) !~ l);
+ bt_assert(l !~ [(2,*)]);
+ bt_assert(l !~ [(one,3..6)]);
+ bt_assert(l ~ [(*,*)]);
+
+ l = add(l, (3,one));
+ l = add(l, (one+one+one,one+one));
+ l = add(l, (3,3));
+ l = add(l, (3,4));
+ l = add(l, (3,5));
+ l2 = filter(l, [(3,*)]);
+ l = delete(l, [(3,2..4)]);
+ bt_assert(l = add(add(add(-empty-, (1,2)), (3,1)), (3,5)));
+ bt_assert(l.len = 3);
+
+ l = add(l, (3,2));
+ l = add(l, (4,5));
+ bt_assert(l = add(add(add(add(add(-empty-, (1,2)), (3,1)), (3,5)), (3,2)), (4,5)));
+
+ bt_assert(l.len = 5);
+ bt_assert(l ~ [(*,2)]);
+ bt_assert(l ~ [(*,5)]);
+ bt_assert(l ~ [(*, one)]);
+ bt_assert(l !~ [(*,3)]);
+ bt_assert(l !~ [(*,(one+6))]);
+ bt_assert(l !~ [(*, (one+one+one))]);
+
+ l = delete(l, [(*,(one+onef(3)))]);
+ l = delete(l, [(*,(4+one))]);
+ bt_assert(l = add(-empty-, (3,1)));
+
+ l = delete(l, [(*,(onef(5)))]);
+ bt_assert(l = -empty-);
+
+ l2 = add(l2, (3,6));
+ l = filter(l2, [(3,1..4)]);
+ l2 = filter(l2, [(3,3..6)]);
+
print "clist A (1..4): ", l;
+ bt_assert(l = add(add(add(add(-empty-, (3,1)), (3,2)), (3,3)), (3,4)));
+
print "clist B (3..6): ", l2;
- print "clist A union B: ", add( l2, l );
+ bt_assert(l2 = add(add(add(add(-empty-, (3,3)), (3,4)), (3,5)), (3,6)));
+
+ print "clist A union B: ", add( l, l2 );
+ bt_assert(add(l, l2) = add(add(add(add(add(add(-empty-, (3,1)), (3,2)), (3,3)), (3,4)), (3,5)), (3,6)));
+
print "clist A isect B: ", filter( l, l2 );
+ bt_assert(filter(l, l2) = add(add(-empty-, (3,3)), (3,4)));
+
print "clist A \ B: ", delete( l, l2 );
+ bt_assert(delete(l, l2) = add(add(-empty-, (3,1)), (3,2)));
+}
+
+bt_test_suite(t_community_list, "Testing communities and lists");
+
+
+
+
+/*
+ * Testing Extended Community List
+ * -------------------------------
+ */
+function t_extended_community_list()
+eclist el;
+eclist el2;
+{
el = -- empty --;
el = add(el, (rt, 10, 20));
el = add(el, (ro, 10.20.30.40, 100));
el = add(el, (ro, 11.21.31.41.mask(16), 200));
+
print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
print el;
- print "EC len: ", el.len;
+ bt_assert(el.len = 3);
el = delete(el, (rt, 10, 20));
el = delete(el, (rt, 10, 30));
+ bt_assert(el = add(add(--empty--, (ro, 10.20.30.40, 100)), (ro, 11.21.0.0, 200)));
el = add(el, (unknown 2, ten, 1));
el = add(el, (unknown 5, ten, 1));
el = add(el, (rt, ten, one+one));
@@ -201,268 +242,688 @@ lclist ll2;
el = add(el, (rt, 10, 5));
el = add(el, (generic, 0x2000a, 3*ten));
el = delete(el, [(rt, 10, 2..ten)]);
- print "EC list (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200) (rt, 10, 1) (unknown 0x5, 10, 1) (rt, 10, 30):";
- print el;
+ bt_assert(el = add(add(add(add(add(--empty--, (ro, 10.20.30.40, 100)), (ro, 11.21.0.0, 200)), (rt, 10, 1)), (unknown 5, 10, 1)), (rt, 10, 30)));
+
el = filter(el, [(rt, 10, *)]);
- print "EC list (rt, 10, 1) (rt, 10, 30): ", el;
- print "Testing EC list, true: ", (rt, 10, 1) ~ el, " ", el ~ [(rt, 10, ten..40)];
- print "Testing EC list, false: ", (rt, 10, 20) ~ el, " ", (ro, 10.20.30.40, 100) ~ el, " ", el ~ [(rt, 10, 35..40)], " ", el ~ [(ro, 10, *)];
+ bt_assert(el = add(add(--empty--, (rt, 10, 1)), (rt, 10, 30)));
+ bt_assert((rt, 10, 1) ~ el);
+ bt_assert(el ~ [(rt, 10, ten..40)]);
+ bt_assert((rt, 10, 20) !~ el);
+ bt_assert((ro, 10.20.30.40, 100) !~ el);
+ bt_assert(el !~ [(rt, 10, 35..40)]);
+ bt_assert(el !~ [(ro, 10, *)]);
+
el = add(el, (rt, 10, 40));
el2 = filter(el, [(rt, 10, 20..40)] );
el2 = add(el2, (rt, 10, 50));
+
print "eclist A (1,30,40): ", el;
+ bt_assert(el = add(add(add(--empty--, (rt, 10, 1)), (rt, 10, 30)), (rt, 10, 40)));
+
print "eclist B (30,40,50): ", el2;
- print "eclist A union B: ", add( el2, el );
- print "eclist A isect B: ", filter( el, el2 );
- print "eclist A \ B: ", delete( el, el2 );
-
- ll = --- empty ---;
- ll = add(ll, (ten, 20, 30));
- ll = add(ll, (1000, 2000, 3000));
- ll = add(ll, mktrip(100000));
- print "LC list (10, 20, 30) (1000, 2000, 3000) (100000, 200000, 300000):";
- print ll;
- print "LC len: ", el.len;
- print "Should be true: ", mktrip(1000) ~ ll, " ", ll ~ [(5,10,15), (10,20,30)], " ", ll ~ [(10,15..25,*)], " ", ll ~ [(ten, *, *)];
- print "Should be false: ", mktrip(100) ~ ll, " ", ll ~ [(5,10,15), (10,21,30)], " ", ll ~ [(10,21..25,*)], " ", ll ~ [(11, *, *)];
- print "LC filtered: ", filter(ll, [(5..15, *, *), (100000, 500..500000, *)]);
-
- ll = --- empty ---;
- ll = add(ll, (10, 10, 10));
- ll = add(ll, (20, 20, 20));
- ll = add(ll, (30, 30, 30));
-
- ll2 = --- empty ---;
- ll2 = add(ll2, (20, 20, 20));
- ll2 = add(ll2, (30, 30, 30));
- ll2 = add(ll2, (40, 40, 40));
-
- print "lclist A (10,20,30): ", ll;
- print "lclist B (20,30,40): ", ll2;
- print "lclist A union B: ", add(ll, ll2);
- print "lclist A isect B: ", filter(ll, ll2);
- print "lclist A \ B: ", delete(ll, ll2);
-
-# test_roa();
-}
-
-function bla()
-{
- print "fifteen called";
- return 15;
+ bt_assert(el2 = add(add(add(--empty--, (rt, 10, 30)), (rt, 10, 40)), (rt, 10, 50)));
+
+ print "eclist A union B: ", add(el2, el);
+ bt_assert(add(el2, el) = add(add(add(add(--empty--, (rt, 10, 30)), (rt, 10, 40)), (rt, 10, 50)), (rt, 10, 1)));
+
+ print "eclist A isect B: ", filter(el, el2);
+ bt_assert(filter(el, el2) = add(add(--empty--, (rt, 10, 30)), (rt, 10, 40)));
+
+ print "eclist A \ B: ", delete(el, el2);
+ bt_assert(delete(el, el2) = add(--empty--, (rt, 10, 1)));
}
-define four=4;
-define onetwo=1.2.3.4;
+bt_test_suite(t_extended_community_list, "Testing extended communities and lists");
-function __test1()
+
+
+
+/*
+ * Testing defined() function
+ * --------------------------
+ */
+
+function test_undef(int a)
+int b;
{
- if source ~ [ RTS_BGP, RTS_STATIC ] then {
-# ospf_metric1 = 65535;
-# ospf_metric2 = 1000;
- ospf_tag = 0x12345678;
- accept;
+ if a = 3 then {
+ b = 4;
+ bt_assert(defined(b));
+ }
+ else {
+ bt_assert(!defined(b));
}
- reject;
}
-function __test2()
+function t_define()
+int i;
{
- if source ~ [ RTS_BGP, RTS_STATIC ] then {
-# ospf_metric1 = 65535;
-# ospf_metric2 = 1000;
- ospf_tag = 0x12345678;
- accept;
- }
- reject;
+ test_undef(2);
+ test_undef(3);
+ test_undef(2);
+
+ bt_assert(defined(1));
+ bt_assert(defined(1.2.3.4));
}
+bt_test_suite(t_define, "Testing defined() function");
-function test_pxset(prefix set pxs)
+
+
+
+/*
+ * Testing quads
+ * -------------
+ */
+
+function t_quad()
+quad qq;
{
- print pxs;
- print " must be true: ", net10 ~ pxs, ",", 10.0.0.0/10 ~ pxs, ",", 10.0.0.0/12 ~ pxs, ",",
- 20.0.0.0/24 ~ pxs, ",", 20.0.40.0/24 ~ pxs, ",", 20.0.0.0/26 ~ pxs, ",",
- 20.0.100.0/26 ~ pxs, ",", 20.0.0.0/28 ~ pxs, ",", 20.0.255.0/28 ~ pxs;
- print " must be false: ", 10.0.0.0/7 ~ pxs, ",", 10.0.0.0/13 ~ pxs, ",", 10.0.0.0/16 ~ pxs, ",",
- 20.0.0.0/16 ~ pxs, ",", 20.0.0.0/23 ~ pxs, ",", 20.0.0.0/29 ~ pxs, ",",
- 11.0.0.0/10 ~ pxs, ",", 20.1.0.0/26 ~ pxs;
+ qq = 1.2.3.4;
+ print "Testinq quad: 1.2.3.4 = ", qq;
+ bt_assert(qq = 1.2.3.4);
+ bt_assert(qq != 4.3.2.1);
}
-function test_undef(int a)
-int b;
+bt_test_suite(t_quad, "Testing quads");
+
+
+
+
+/*
+ * Testing sets of quads
+ * ---------------------
+ */
+
+function t_quad_set()
+quad qq;
{
- if a = 3
- then b = 4;
- print "Defined: ", a, " ", b, " ", defined(b);
+ qq = 1.2.3.4;
+ bt_assert(qq ~ [1.2.3.4, 5.6.7.8]);
+ bt_assert(qq !~ [1.2.1.1, 1.2.3.5]);
}
-define is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19];
-define is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2];
-define is3 = [5, 17, 2, 11, 8, 15, 3, 19];
+bt_test_suite(t_quad_set, "Testing sets of quads");
-define pxs2 = [ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ];
+
+
+
+/*
+ * Testing Extended Communities
+ * ----------------------------
+ */
+
+function t_ec()
+ec cc;
+{
+ cc = (rt, 12345, 200000);
+ print "Testing EC: ", cc;
+
+ bt_assert(cc = (rt, 12345, 200000));
+ bt_assert(cc < (rt, 12345, 200010));
+ bt_assert(cc != (rt, 12346, 200000));
+ bt_assert(cc != (ro, 12345, 200000));
+ bt_assert(!(cc > (rt, 12345, 200010)));
+
+ print "Testing EC: (ro, 100000, 20000) = ", (ro, 100000, 20000);
+}
+
+bt_test_suite(t_ec, "Testing Extended Communities");
+
+
+
+
+/*
+ * Testing sets of Extended Communities
+ * ------------------------------------
+ */
define ecs2 = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
+function t_ec_set()
+ec set ecs;
+{
+ ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
+ print "EC set (rt, 10, 20) (ro, 100000, 100..200), (rt, 12345, *):";
+ print ecs;
+ print ecs2;
+
+ bt_assert((rt, 10, 20) ~ ecs);
+ bt_assert((ro, 100000, 100) ~ ecs);
+ bt_assert((ro, 100000, 128) ~ ecs);
+ bt_assert((ro, 100000, 200) ~ ecs);
+ bt_assert((rt, 12345, 0) ~ ecs);
+ bt_assert((rt, 12345, 200000) ~ ecs);
+ bt_assert((rt, 12345, 4000000) ~ ecs);
+ bt_assert((ro, 10, 20) !~ ecs);
+ bt_assert((rt, 10, 21) !~ ecs);
+ bt_assert((ro, 100000, 99) !~ ecs);
+ bt_assert((ro, 12345, 10) !~ ecs);
+ bt_assert((rt, 12346, 0) !~ ecs);
+ bt_assert((ro, 0.1.134.160, 150) !~ ecs);
+}
+
+bt_test_suite(t_ec_set, "Testing sets of Extended Communities");
+
+
+
+
+/*
+ * Testing integers
+ * ----------------
+ */
+
+define four = 4;
+define xyzzy = (120+10);
+define '1a-a1' = (xyzzy-100);
-function __startup()
+function t_int()
int i;
-bool b;
-prefix px;
-ip p;
-pair pp;
-quad qq;
-ec cc;
+{
+ bt_assert(xyzzy = 130);
+ bt_assert('1a-a1' = 30);
+
+ i = four;
+ i = 12*100 + 60/2 + i;
+ i = (i + 0);
+ bt_assert(i = 1234);
+
+ if (i = 4) then
+ bt_assert(false);
+ else
+ bt_assert(true);
+
+ if !(i = 3) then
+ bt_assert(true);
+ else
+ bt_assert(false);
+
+ if 1234 = i then
+ bt_assert(true);
+ else
+ bt_assert(false);
+
+ if 1 <= 1 then
+ bt_assert(true);
+ else
+ bt_assert(false);
+
+ if 1234 < 1234 then
+ bt_assert(false);
+ else
+ bt_assert(true);
+
+ i = 4200000000;
+ bt_assert(i = 4200000000);
+ bt_assert(i > 4100000000);
+ bt_assert(!(i > 4250000000));
+
+ bt_assert(1 = 1);
+ bt_assert(!(1 != 1));
+
+ bt_assert(1 != 2);
+ bt_assert(1 <= 2);
+
+ bt_assert(1 != "a");
+ bt_assert(1 != (0,1));
+}
+
+bt_test_suite(t_int, "Testing integers");
+
+
+
+
+/*
+ * Testing sets of integers
+ * ------------------------
+ */
+
+define is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19];
+define is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2];
+define is3 = [5, 17, 2, 11, 8, 15, 3, 19];
+
+function t_int_set()
int set is;
-pair set ps;
-ec set ecs;
-ip set ips;
-prefix set pxs;
-string st;
{
- print "1a-a1 = 30: ", '1a-a1';
- print "Testing filter language:";
- i = four;
- i = 12*100 + 60/2 + i;
- i = ( i + 0 );
- print " arithmetics: 1234 = ", i;
- printn " if statements ";
- print "what happens here?";
- printn ".";
- if (i = 4) then { print "*** FAIL: if 0"; quitbird; } else printn ".";
-# if !(i = 3) then { print "*** FAIL: if 0"; quitbird; } else printn ".";
- if 1234 = i then printn "."; else { print "*** FAIL: if 1 else"; }
-# if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; }
- if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok";
+ bt_assert(1 ~ [1,2,3]);
+ bt_assert(5 ~ [1..20]);
+ bt_assert(2 ~ [ 1, 2, 3 ]);
+ bt_assert(5 ~ [ 4 .. 7 ]);
+ bt_assert(1 !~ [ 2, 3, 4 ]);
+
is = [ 2, 3, 4, 7..11 ];
+ bt_assert(10 ~ is);
+ bt_assert(5 !~ is);
+
+ bt_assert(1 ~ is1);
+ bt_assert(3 ~ is1);
+ bt_assert(5 ~ is1);
+ bt_assert((one+2) ~ is1);
+ bt_assert(2 ~ is2);
+ bt_assert(2 ~ is3);
+ bt_assert(4 !~ is1);
+ bt_assert(4 !~ is2);
+ bt_assert(4 !~ is3);
+ bt_assert(10 !~ is1);
+ bt_assert(10 !~ is2);
+ bt_assert(10 !~ is3);
+ bt_assert(15 ~ is1);
+ bt_assert(15 ~ is2);
+ bt_assert(15 ~ is3);
+ bt_assert(18 !~ is1);
+ bt_assert(18 !~ is2);
+ bt_assert(18 !~ is3);
+ bt_assert(19 ~ is1);
+ bt_assert(19 ~ is2);
+ bt_assert(19 ~ is3);
+ bt_assert(20 !~ is1);
+ bt_assert(20 !~ is2);
+ bt_assert(20 !~ is3);
+
+ bt_assert([1,2] != [1,3]);
+ bt_assert([1,4..10,20] = [1,4..10,20]);
- print "must be true: ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- ,
- " ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ];
- print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ ,
- " ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ];
+ print "What will this do? ", [ 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 5 ];
+}
- print " must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ];
- print " data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ];
- print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a");
+bt_test_suite(t_int_set, "Testing sets of integers");
- print " must be true: ", defined(1), ",", defined(1.2.3.4), ",", 1 != 2, ",", 1 <= 2;
- print " data types: must be false: ", 1 ~ [ 2, 3, 4 ], ",", 5 ~ is, ",", 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ], ",", (1,2) > (2,2), ",", (1,1) > (1,1), ",", 1.0.0.0/9 ~ [ 1.0.0.0/8- ], ",", 1.2.0.0/17 ~ [ 1.0.0.0/8{ 15 , 16 } ], ",", true && false;
- print " must be true: ", 1 ~ is1, " ", 3 ~ is1, " ", 5 ~ is1;
- print " must be true: ", (one+2) ~ is1, " ", 2 ~ is2, " ", 2 ~ is3;
- print " must be false: ", 4 ~ is1, " ", 4 ~ is2, " ", 4 ~ is3;
- print " must be false: ", 10 ~ is1, " ", 10 ~ is2, " ", 10 ~ is3;
- print " must be true: ", 15 ~ is1, " ", 15 ~ is2, " ", 15 ~ is3;
- print " must be false: ", 18 ~ is1, " ", 18 ~ is2, " ", 18 ~ is3;
- print " must be true: ", 19 ~ is1, " ", 19 ~ is2, " ", 19 ~ is3;
- print " must be false: ", 20 ~ is1, " ", 20 ~ is2, " ", 20 ~ is3;
- px = 1.2.0.0/18;
- print "Testing prefixes: 1.2.0.0/18 = ", px;
- print " must be true: ", 192.168.0.0/16 ~ 192.168.0.0/16, " ", 192.168.0.0/17 ~ 192.168.0.0/16, " ", 192.168.254.0/24 ~ 192.168.0.0/16, " ", netdoc ~ 2001::/16;
- print " must be false: ", 192.168.0.0/15 ~ 192.168.0.0/16, " ", 192.160.0.0/17 ~ 192.168.0.0/16, " ", px ~ netdoc;
+/*
+ * Testing ip address
+ * ------------------
+ */
+
+define onetwo = 1.2.3.4;
+function t_ip()
+ip p;
+{
p = 127.1.2.3;
- print "Testing mask : 127.0.0.0 = ", p.mask(8);
+ bt_assert(p.mask(8) = 127.0.0.0);
+ bt_assert(1.2.3.4 = 1.2.3.4);
+ bt_assert(1.2.3.4 = onetwo);
+ print "1.2.3.4 = ", onetwo;
+}
+
+bt_test_suite(t_ip, "Testing ip address");
+
+
+
+
+/*
+ * Testing sets of ip address
+ * --------------------------
+ */
+
+function t_ip_set()
+{
+ bt_assert(1.2.3.4 !~ [ 1.2.3.3, 1.2.3.5 ]);
+ bt_assert(1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ]);
+}
+
+bt_test_suite(t_ip_set, "Testing sets of ip address");
+
+
+
+/*
+ * Testing enums
+ * -------------
+ */
+
+function t_enum()
+{
+ print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC;
+ bt_assert(RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE]);
+ bt_assert(RTS_BGP !~ [RTS_STATIC, RTS_DEVICE]);
+}
+
+bt_test_suite(t_enum, "Testing enums");
+
+
+
+
+/*
+ * Testing pairs
+ * -------------
+ */
+
+function 'mkpair-a'(int a)
+{
+ return (1, a);
+}
+
+function t_pair()
+pair pp;
+{
pp = (1, 2);
- print "Testing pairs: (1,2) = ", (1,2), " = ", pp, " = ", (1,1+1), " = ", 'mkpair-a'(2);
- print " must be true: ", (1,2) = (1,1+1);
- print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC, " ",
- ", true: ", RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE],
- ", false: ", RTS_BGP ~ [RTS_STATIC, RTS_DEVICE];
+ bt_assert((1,2) = pp);
+ bt_assert((1,1+1) = pp);
+ bt_assert('mkpair-a'(2) = pp);
+ bt_assert((1,2) = (1,1+1));
+ bt_assert(((1,2) < (2,2)));
+ bt_assert(!((1,1) > (1,1)));
+}
+
+bt_test_suite(t_pair, "Testing pairs");
+
+
+
+/*
+ * Testing sets of pairs
+ * ---------------------
+ */
+
+function t_pair_set()
+pair pp;
+pair set ps;
+{
+ pp = (1, 2);
ps = [(1,(one+one)), (3,4)..(4,8), (5,*), (6,3..6)];
print "Pair set: ", ps;
- print "Testing pair set, true: ", pp ~ ps, " ", (3,5) ~ ps, " ", (4,1) ~ ps, " ", (5,4) ~ ps, " ", (5,65535) ~ ps, " ", (6,4) ~ ps, " ", (3, 10000) ~ ps;
- print "Testing pair set, false: ", (3,3) ~ ps, " ", (4,9) ~ ps, " ", (4,65535) ~ ps, " ", (6,2) ~ ps, " ", (6,6+one) ~ ps, " ", ((one+6),2) ~ ps, " ", (1,1) ~ ps;
+ bt_assert(pp ~ ps);
+ bt_assert((3,5) ~ ps);
+ bt_assert((4,1) ~ ps);
+ bt_assert((5,4) ~ ps);
+ bt_assert((5,65535) ~ ps);
+ bt_assert((6,4) ~ ps);
+ bt_assert((3, 10000) ~ ps);
+ bt_assert((3,3) !~ ps);
+ bt_assert((4,9) !~ ps);
+ bt_assert((4,65535) !~ ps);
+ bt_assert((6,2) !~ ps);
+ bt_assert((6,6+one) !~ ps);
+ bt_assert(((one+6),2) !~ ps);
+ bt_assert((1,1) !~ ps);
ps = [(20..150, 200..300), (50100..50200, 1000..50000), (*, 5+5)];
- print "Pair set: .. too long ..";
- print "Testing pair set, true: ", (100,200) ~ ps, " ", (150,300) ~ ps, " ", (50180,1200) ~ ps, " ", (50110,49000) ~ ps, " ", (0,10) ~ ps, " ", (64000,10) ~ ps;
- print "Testing pair set, false: ", (20,199) ~ ps, " ", (151,250) ~ ps, " ", (50050,2000) ~ ps, " ", (50150,50050) ~ ps, " ", (10,9) ~ ps, " ", (65535,11) ~ ps ;
+ print "Pair set: ", ps;
+ bt_assert((100,200) ~ ps);
+ bt_assert((150,300) ~ ps);
+ bt_assert((50180,1200) ~ ps);
+ bt_assert((50110,49000) ~ ps);
+ bt_assert((0,10) ~ ps);
+ bt_assert((64000,10) ~ ps);
+ bt_assert((20,199) !~ ps);
+ bt_assert((151,250) !~ ps);
+ bt_assert((50050,2000) !~ ps);
+ bt_assert((50150,50050) !~ ps);
+ bt_assert((10,9) !~ ps);
+ bt_assert((65535,11) !~ ps);
+}
- qq = 1.2.3.4;
- print "Testinq quad: 1.2.3.4 = ", qq,
- ", true: ", qq = 1.2.3.4, " ", qq ~ [1.2.3.4, 5.6.7.8],
- ", false: ", qq = 4.3.2.1, " ", qq ~ [1.2.1.1, 1.2.3.5];
+bt_test_suite(t_pair_set, "Testing sets of pairs");
- cc = (rt, 12345, 200000);
- print "Testing EC: (rt, 12345, 200000) = ", cc;
- print "Testing EC: (ro, 100000, 20000) = ", (ro, 100000, 20000);
- print "Testing EC: (rt, 10.20.30.40, 20000) = ", (rt, 10.20.30.40, 20000);
- print " true: ", cc = (rt, 12345, 200000), " ", cc < (rt, 12345, 200010),
- ", false: ", cc = (rt, 12346, 200000), " ", cc = (ro, 12345, 200000), " ", cc > (rt, 12345, 200010);
- ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
- print "EC set: ", ecs;
- print "EC set: ", ecs2;
- print "Testing EC set, true: ", (rt, 10, 20) ~ ecs, " ", (ro, 100000, 100) ~ ecs, " ", (ro, 100000, 200) ~ ecs,
- " ", (rt, 12345, 0) ~ ecs, " ", cc ~ ecs, " ", (rt, 12345, 4000000) ~ ecs;
- print "Testing EC set, false: ", (ro, 10, 20) ~ ecs, " ", (rt, 10, 21) ~ ecs, " ", (ro, 100000, 99) ~ ecs,
- " ", (ro, 12345, 10) ~ ecs, " ", (rt, 12346, 0) ~ ecs, " ", (ro, 0.1.134.160, 150) ~ ecs;
+
+/*
+ * Testing string matching
+ * -----------------------
+ */
+
+function t_string()
+string st;
+{
st = "Hello";
- print "Testing string: ", st, " true: ", st ~ "Hell*", " false: ", st ~ "ell*";
-
+ print "Testing string: ", st;
+ bt_assert(st ~ "Hell*");
+ bt_assert(st ~ "?ello");
+ bt_assert(st ~ "Hello");
+ bt_assert(st ~ "Hell?");
+ bt_assert(st !~ "ell*");
+}
+
+bt_test_suite(t_string, "Testing string matching");
+
+
+
+
+/*
+ * Testing boolean expressions
+ * ---------------------------
+ */
+
+function t_bool()
+bool b;
+{
b = true;
- print "Testing bool: ", b, ", ", !b;
+ bt_assert(b);
+ bt_assert(!!b);
+
+ if ( b = true ) then
+ bt_assert(b);
+ else
+ bt_assert(false);
+
+ bt_assert(true && true);
+ bt_assert(true || false);
+ bt_assert(! false && ! false && true);
+ bt_assert(1 < 2 && 1 != 3);
+ bt_assert(true && true && ! false);
+ bt_assert(true || 1+"a");
+ bt_assert(!(false && 1+"a"));
+ bt_assert(!(true && false));
+}
- if ( b = true ) then print "Testing bool comparison b = true: ", b;
- else { print "*** FAIL: TRUE test failed" ; quitbird; }
-
- ips = [ 1.1.1.0 .. 1.1.1.255, ip1222];
- print "Testing IP sets: ";
- print ips;
- print " must be true: ", 1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips;
- print " must be false: ", 1.1.0.255 ~ ips, ",", 1.1.2.0 ~ ips, ",", 1.2.2.3 ~ ips, ",", 192.168.1.1 ~ ips;
+bt_test_suite(t_bool, "Testing boolean expressions");
- pxs = [ 1.2.0.0/16, 1.4.0.0/16+];
- print "Testing prefix sets: ";
+
+
+
+/*
+ * Testing prefixes
+ * ----------------
+ */
+
+define netdoc = 2001:db8::/32;
+
+function t_prefix()
+prefix px;
+{
+ px = 1.2.0.0/18;
+ print "Testing prefixes: 1.2.0.0/18 = ", px;
+ bt_assert(192.168.0.0/16 ~ 192.168.0.0/16);
+ bt_assert(192.168.0.0/17 ~ 192.168.0.0/16);
+ bt_assert(192.168.254.0/24 ~ 192.168.0.0/16);
+ bt_assert(netdoc ~ 2001::/16);
+ bt_assert(192.168.0.0/15 !~ 192.168.0.0/16);
+ bt_assert(192.160.0.0/17 !~ 192.168.0.0/16);
+ bt_assert(px !~ netdoc);
+
+ bt_assert(1.2.3.4 ~ 1.0.0.0/8);
+ bt_assert(1.0.0.0/8 ~ 1.0.0.0/8);
+}
+
+bt_test_suite(t_prefix, "Testing prefixes");
+
+
+
+
+/*
+ * Testing prefix sets
+ * -------------------
+ */
+
+define net10 = 10.0.0.0/8;
+define pxs2 = [ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ];
+
+function test_pxset(prefix set pxs)
+{
print pxs;
- print " must be true: ", 1.2.0.0/16 ~ pxs, ",", 1.4.0.0/16 ~ pxs, ",", 1.4.0.0/18 ~ pxs, ",", 1.4.0.0/32 ~ pxs;
- print " must be false: ", 1.1.0.0/16 ~ pxs, ",", 1.3.0.0/16 ~ pxs, ",", 1.2.0.0/15 ~ pxs, ",", 1.2.0.0/17 ~ pxs, ",",
- 1.2.0.0/32 ~ pxs, ",", 1.4.0.0/15 ~ pxs;
+
+ bt_assert(net10 ~ pxs);
+ bt_assert(10.0.0.0/10 ~ pxs);
+ bt_assert(10.0.0.0/12 ~ pxs);
+ bt_assert(20.0.0.0/24 ~ pxs);
+ bt_assert(20.0.40.0/24 ~ pxs);
+ bt_assert(20.0.0.0/26 ~ pxs);
+ bt_assert(20.0.100.0/26 ~ pxs);
+ bt_assert(20.0.0.0/28 ~ pxs);
+ bt_assert(20.0.255.0/28 ~ pxs);
+
+ bt_assert(10.0.0.0/7 !~ pxs);
+ bt_assert(10.0.0.0/13 !~ pxs);
+ bt_assert(10.0.0.0/16 !~ pxs);
+ bt_assert(20.0.0.0/16 !~ pxs);
+ bt_assert(20.0.0.0/23 !~ pxs);
+ bt_assert(20.0.0.0/29 !~ pxs);
+ bt_assert(11.0.0.0/10 !~ pxs);
+ bt_assert(20.1.0.0/26 !~ pxs);
+
+ bt_assert(1.0.0.0/8 ~ [ 1.0.0.0/8+ ]);
+ bt_assert(1.0.0.0/9 !~ [ 1.0.0.0/8- ]);
+ bt_assert(1.2.0.0/17 !~ [ 1.0.0.0/8{ 15 , 16 } ]);
+
+ bt_assert([ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ]);
+}
+
+function t_prefix_sets()
+prefix set pxs;
+{
+ pxs = [ 1.2.0.0/16, 1.4.0.0/16+];
+ print "Testing prefix sets: ", pxs;
+ bt_assert(1.2.0.0/16 ~ pxs);
+ bt_assert(1.4.0.0/16 ~ pxs);
+ bt_assert(1.4.0.0/18 ~ pxs);
+ bt_assert(1.4.0.0/32 ~ pxs);
+ bt_assert(1.1.0.0/16 !~ pxs);
+ bt_assert(1.3.0.0/16 !~ pxs);
+ bt_assert(1.2.0.0/15 !~ pxs);
+ bt_assert(1.2.0.0/17 !~ pxs);
+ bt_assert(1.2.0.0/32 !~ pxs);
+ bt_assert(1.4.0.0/15 !~ pxs);
test_pxset(pxs2);
test_pxset([ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ]);
- print "What will this do? ", [ 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 5 ];
- print "Testing functions...";
- callme ( 1, 2 );
- callme ( 2, 2 );
- callme ( 2, 2 );
- callme ( 3, 2 );
- callme ( 4, 4 );
- callme ( 7, 2 );
+ bt_assert(1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ]);
+ bt_assert([ 10.0.0.0/8{ 15 , 17 } ] != [ 11.0.0.0/8{ 15 , 17 } ]);
+}
- i = fifteen();
- print "Testing function calls: 15 = ", i;
+bt_test_suite(t_prefix_sets, "Testing prefix sets");
- path_test();
- print "1.2.3.4 = ", onetwo;
- i = 4200000000;
- print "4200000000 = ", i, " true: ", i = 4200000000, " ", i > 4100000000, " false: ", i > 4250000000;
- test_undef(2);
- test_undef(3);
- test_undef(2);
+/*
+ * Testing IP sets
+ * ---------------
+ */
- print "Testing include";
- include "test.conf.inc";
+define ip1222 = 1.2.2.2;
- print "done";
- quitbird;
-# print "*** FAIL: this is unreachable";
+function t_ip_sets()
+ip set ips;
+{
+ ips = [ 1.1.1.0 .. 1.1.1.255, ip1222];
+ print "Testing IP sets: ", ips;
+ bt_assert(1.1.1.0 ~ ips);
+ bt_assert(1.1.1.100 ~ ips);
+ bt_assert(1.2.2.2 ~ ips);
+ bt_assert(1.1.0.255 !~ ips);
+ bt_assert(1.1.2.0 !~ ips);
+ bt_assert(1.2.2.3 !~ ips);
+ bt_assert(192.168.1.1 !~ ips);
}
-filter testf
-int j;
-{
+bt_test_suite(t_ip_sets, "Testing IP sets");
+
+
+
+
+/*
+ * Testing calling functions
+ * -------------------------
+ */
+
+function callme(int arg1; int arg2)
+int i;
+{
+ case arg1 {
+ 1, 42: return 42;
+ else: return arg1 * arg2;
+ }
+
+ return 0;
+}
+
+function fifteen()
+{
+ return 15;
+}
+
+function t_call_function()
+{
+ bt_assert(fifteen() = 15);
+
+ bt_assert(callme(1, 2) = 42);
+ bt_assert(callme(42, 2) = 42);
+
+ bt_assert(callme(2, 2) = 4);
+ bt_assert(callme(3, 2) = 6);
+ bt_assert(callme(4, 4) = 16);
+ bt_assert(callme(7, 2) = 14);
+}
+
+bt_test_suite(t_call_function, "Testing calling functions");
+
+
+
+
+/*
+ * Test including another config file
+ * ----------------------------------
+ */
+
+function t_include()
+int i;
+{
+ print "Testing include";
+ i = 1;
+ include "test.conf.inc";
+ bt_assert(i = 42);
+}
+
+bt_test_suite(t_include, "Test including another config file");
+
+
+
+
+/*
+ * Unused functions -- testing only parsing
+ * ----------------------------------------
+ */
+
+function __test1()
+{
+ if source ~ [ RTS_BGP, RTS_STATIC ] then {
+# ospf_metric1 = 65535;
+# ospf_metric2 = 1000;
+ ospf_tag = 0x12345678;
+ accept;
+ }
+ reject;
+}
+
+function __test2()
+{
+ if source ~ [ RTS_BGP, RTS_STATIC ] then {
+# ospf_metric1 = 65535;
+# ospf_metric2 = 1000;
+ ospf_tag = 0x12345678;
+ accept;
+ }
+ reject;
+}
+
+filter testf
+int j;
+{
print "Heya, filtering route to ", net.ip, " prefixlen ", net.len, " source ", source;
print "This route was from ", from;
j = 7;
@@ -472,8 +933,34 @@ int j;
}
rip_metric = 14;
unset(rip_metric);
-
+
accept "ok I take that";
}
-eval __startup();
+/*
+roa table rl
+{
+ roa 10.110.0.0/16 max 16 as 1000;
+ roa 10.120.0.0/16 max 24 as 1000;
+ roa 10.130.0.0/16 max 24 as 2000;
+ roa 10.130.128.0/18 max 24 as 3000;
+}
+
+function test_roa()
+{
+ # cannot be tested in __startup(), sorry
+ print "Testing ROA";
+ print "Should be true: ", roa_check(rl, 10.10.0.0/16, 1000) = ROA_UNKNOWN,
+ " ", roa_check(rl, 10.0.0.0/8, 1000) = ROA_UNKNOWN,
+ " ", roa_check(rl, 10.110.0.0/16, 1000) = ROA_VALID,
+ " ", roa_check(rl, 10.110.0.0/16, 2000) = ROA_INVALID,
+ " ", roa_check(rl, 10.110.32.0/20, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.120.32.0/20, 1000) = ROA_VALID;
+ print "Should be true: ", roa_check(rl, 10.120.32.0/20, 2000) = ROA_INVALID,
+ " ", roa_check(rl, 10.120.32.32/28, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 1000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 2000) = ROA_VALID,
+ " ", roa_check(rl, 10.130.30.0/24, 3000) = ROA_INVALID,
+ " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID;
+}
+*/ \ No newline at end of file
diff --git a/filter/test.conf.inc b/filter/test.conf.inc
index 109a49c5..7707ae38 100644
--- a/filter/test.conf.inc
+++ b/filter/test.conf.inc
@@ -2,4 +2,5 @@
print "Entering include";
print "Should be 2: ", 1+1;
print "Leaving include";
+i = 42;
diff --git a/filter/test.conf2 b/filter/test.conf2
index 60bdd965..2a5d896b 100644
--- a/filter/test.conf2
+++ b/filter/test.conf2
@@ -18,6 +18,7 @@ protocol direct {
protocol kernel {
disabled;
+ ipv4; # Must be specified at least one channel
# learn; # Learn all routes from the kernel
# scan time 10; # Scan kernel tables every 10 seconds
}
@@ -25,51 +26,58 @@ protocol kernel {
protocol static {
# disabled;
- import filter { print "ahoj";
- print source;
- if source = RTS_STATIC then {
- print "It is from static";
- }
- print from;
- from = 1.2.3.4;
- print from;
- print scope;
- scope = SCOPE_HOST;
- print scope;
- if !(scope ~ [ SCOPE_HOST, SCOPE_SITE ]) then {
- print "Failed in test";
- quitbird;
- }
-
- preference = 15;
- print preference;
- preference = 29;
- print preference;
- rip_metric = 1;
- print rip_metric;
- rip_metric = rip_metric + 5;
- print rip_metric;
- bgp_community = - empty - ;
- print "nazdar";
- bgp_community = add(bgp_community, (1,2));
- print "cau";
- bgp_community = add(bgp_community, (2,3));
- bgp_community.add((4,5));
- print "community = ", bgp_community;
- bgp_community.delete((2,3));
- print "community = ", bgp_community;
- bgp_community.empty;
- print "community = ", bgp_community;
- print "done";
- };
+ ipv4 {
+ export all;
+
+ import filter {
+ print "ahoj";
+ print source;
+ if source = RTS_STATIC then {
+ print "It is from static";
+ }
+ print from;
+ from = 1.2.3.4;
+ print from;
+ print scope;
+ scope = SCOPE_HOST;
+ print scope;
+ if !(scope ~ [ SCOPE_HOST, SCOPE_SITE ]) then {
+ print "Failed in test";
+ quitbird;
+ }
+ preference = 15;
+ print preference;
+ preference = 29;
+ print preference;
+ rip_metric = 1;
+ print rip_metric;
+ rip_metric = rip_metric + 5;
+ print rip_metric;
+
+#
+# TODO: uncomment this part after finishing BGP integration version
+#
+# bgp_community = -empty-;
+# print "hi";
+# bgp_community = add(bgp_community, (1,2));
+# print "hello";
+# bgp_community = add(bgp_community, (2,3));
+# bgp_community.add((4,5));
+# print "community = ", bgp_community;
+# bgp_community.delete((2,3));
+# print "community = ", bgp_community;
+# bgp_community.empty;
+# print "community = ", bgp_community;
+# print "done";
+ };
+ };
route 0.0.0.0/0 via 195.113.31.113;
route 62.168.0.0/25 reject;
route 1.2.3.4/32 via 195.113.31.124;
-# route 10.0.0.0/8 reject;
-# route 10.1.1.0:255.255.255.0 via 62.168.0.3;
-# route 10.1.2.0:255.255.255.0 via 62.168.0.3;
-# route 10.1.3.0:255.255.255.0 via 62.168.0.4;
-# route 10.2.0.0/24 via "arc0";
- export all;
+ route 10.0.0.0/8 reject;
+ route 10.1.1.0:255.255.255.0 via 62.168.0.3;
+ route 10.1.2.0:255.255.255.0 via 62.168.0.3;
+ route 10.1.3.0:255.255.255.0 via 62.168.0.4;
+ route 10.2.0.0/24 via "arc0";
}
diff --git a/filter/test6.conf b/filter/test6.conf
index f25ffc47..fb82cf6b 100644
--- a/filter/test6.conf
+++ b/filter/test6.conf
@@ -9,6 +9,8 @@ router id 62.168.0.1;
define xyzzy = (120+10);
+protocol device {}
+
function callme(int arg1; int arg2)
int local1;
int local2;
@@ -30,7 +32,7 @@ function fifteen()
return 15;
}
-function paths()
+function _paths()
bgpmask pm1;
bgpmask pm2;
bgppath p2;
@@ -97,7 +99,7 @@ ip p;
pair pp;
int set is;
prefix set pxs;
-string s;
+string str;
{
print "Testing filter language:";
i = four;
@@ -129,8 +131,8 @@ string s;
print "Testing pairs: (1,2) = ", (1,2), " = ", pp;
print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC;
- s = "Hello";
- print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*";
+ str = "Hello";
+ print "Testing string: ", str, " true: ", str ~ "Hell*", " false: ", str ~ "ell*";
b = true;
print "Testing bool: ", b, ", ", !b;
@@ -156,11 +158,12 @@ string s;
i = fifteen();
print "Testing function calls: 15 = ", i;
- paths();
+ _paths();
print "done";
- quitbird;
-# print "*** FAIL: this is unreachable";
+ return 0;
+ print "*** FAIL: this is unreachable";
+ quitbird; # quit with err exit code 1
}
filter testf
diff --git a/filter/test_bgp_filtering.conf b/filter/test_bgp_filtering.conf
new file mode 100644
index 00000000..573cad46
--- /dev/null
+++ b/filter/test_bgp_filtering.conf
@@ -0,0 +1,113 @@
+router id 62.168.0.1;
+
+function net_martian()
+{
+ return net ~ [ 169.254.0.0/16+, 172.16.0.0/12+, 192.168.0.0/16+, 10.0.0.0/8+,
+ 127.0.0.0/8+, 224.0.0.0/4+, 240.0.0.0/4+, 0.0.0.0/32-, 0.0.0.0/0{25,32}, 0.0.0.0/0{0,7} ];
+}
+
+function net_local()
+{
+ return net ~ [ 12.10.0.0/16+, 34.10.0.0/16+ ];
+}
+
+function rt_import(int asn; int set peer_asns; prefix set peer_nets)
+{
+ if ! (net ~ peer_nets) then return false;
+ if ! (bgp_path.last ~ peer_asns) then return false;
+ if bgp_path.first != asn then return false;
+ if bgp_path.len > 64 then return false;
+ if bgp_next_hop != from then return false;
+ return true;
+}
+
+function rt_import_all(int asn)
+{
+ if net_martian() || net_local() then return false;
+ if bgp_path.first != asn then return false;
+ if bgp_path.len > 64 then return false;
+ if bgp_next_hop != from then return false;
+ return true;
+}
+
+function rt_import_rs(int asn)
+{
+ if net_martian() || net_local() then return false;
+ if bgp_path.len > 64 then return false;
+ return true;
+}
+
+function rt_export()
+{
+ if proto = "static_bgp" then return true;
+ if source != RTS_BGP then return false;
+ if net_martian() then return false;
+ if bgp_path.len > 64 then return false;
+ # return bgp_next_hop ~ [ 100.1.1.1, 100.1.1.2, 200.1.1.1 ];
+ return bgp_path.first ~ [ 345, 346 ];
+}
+
+
+function rt_export_all()
+{
+ if proto = "static_bgp" then return true;
+ if source != RTS_BGP then return false;
+ if net_martian() then return false;
+ if bgp_path.len > 64 then return false;
+ return true;
+}
+
+filter bgp_in_uplink_123
+{
+ if ! rt_import_all(123) then reject;
+ accept;
+}
+
+filter bgp_out_uplink_123
+{
+ if ! rt_export() then reject;
+ accept;
+}
+
+
+filter bgp_in_peer_234
+{
+ if ! rt_import(234, [ 234, 1234, 2345, 3456 ],
+ [ 12.34.0.0/16, 23.34.0.0/16, 34.56.0.0/16 ])
+ then reject;
+ accept;
+}
+
+filter bgp_out_peer_234
+{
+ if ! rt_export() then reject;
+ accept;
+}
+
+filter bgp_in_rs
+{
+ if ! rt_import_rs(bgp_path.last) then reject;
+ accept;
+}
+
+filter bgp_out_rs
+{
+ if ! rt_export() then reject;
+ accept;
+}
+
+
+filter bgp_in_client_345
+{
+ if ! rt_import(345, [ 345 ], [ 34.5.0.0/16 ]) then reject;
+ accept;
+}
+
+filter bgp_out_client_345
+{
+ if ! rt_export_all() then reject;
+ accept;
+}
+
+
+
diff --git a/filter/tree_test.c b/filter/tree_test.c
new file mode 100644
index 00000000..abe955d0
--- /dev/null
+++ b/filter/tree_test.c
@@ -0,0 +1,304 @@
+/*
+ * Filters: Utility Functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "filter/filter.h"
+#include "conf/conf.h"
+
+#define MAX_TREE_HEIGHT 13
+
+static void
+start_conf_env(void)
+{
+ bt_bird_init();
+
+ pool *p = rp_new(&root_pool, "helper_pool");
+ linpool *l = lp_new(p, 4080);
+ cfg_mem = l;
+}
+
+static struct f_tree *
+new_tree(uint id)
+{
+ struct f_tree *tree = f_new_tree();
+ tree->from.type = tree->to.type = T_INT;
+ tree->from.val.i = tree->to.val.i = id;
+
+ return tree;
+}
+
+/*
+ * Show subtree in infix notation
+ */
+static void
+show_subtree(struct f_tree *node)
+{
+ if (!node)
+ return;
+
+ show_subtree(node->left);
+
+ if (node->from.val.i == node->to.val.i)
+ bt_debug("%u ", node->from.val.i);
+ else
+ bt_debug("%u..%u ", node->from.val.i, node->to.val.i);
+
+ show_subtree(node->right);
+}
+
+static void
+show_tree2(struct f_tree *root_node, const char *tree_name)
+{
+ bt_debug("%s: \n", tree_name);
+ bt_debug("[ ");
+ show_subtree(root_node);
+ bt_debug("]\n\n");
+}
+
+#define show_tree(tree) show_tree2(tree, #tree);
+
+static uint
+get_nodes_count_full_bin_tree(uint height)
+{
+ return (bt_naive_pow(2, height+1) - 1);
+}
+
+static struct f_tree *
+get_balanced_full_subtree(uint height, uint idx)
+{
+ struct f_tree *node = new_tree(idx);
+ if (height > 0)
+ {
+ uint nodes_in_subtree = get_nodes_count_full_bin_tree(--height);
+ node->left = get_balanced_full_subtree(height, idx - nodes_in_subtree/2 - 1);
+ node->right = get_balanced_full_subtree(height, idx + nodes_in_subtree/2 + 1);
+ }
+ return node;
+}
+
+static struct f_tree *
+get_balanced_full_tree(uint height)
+{
+ return get_balanced_full_subtree(height, get_nodes_count_full_bin_tree(height)/2);
+}
+
+static struct f_tree *
+get_degenerated_left_tree(uint nodes_count)
+{
+ struct f_tree *old = NULL;
+ struct f_tree *new = NULL;
+ uint i;
+
+ for (i = 0; i < nodes_count; i++)
+ {
+ old = new;
+ new = new_tree(nodes_count-1-i);
+ new->left = old;
+ }
+
+ return new;
+}
+
+static struct f_tree *
+get_random_degenerated_left_tree(uint nodes_count)
+{
+ struct f_tree *tree = get_degenerated_left_tree(nodes_count);
+
+ size_t avaible_indexes_size = nodes_count * sizeof(byte);
+ byte *avaible_indexes = malloc(avaible_indexes_size);
+ memset(avaible_indexes, 0, avaible_indexes_size);
+
+ struct f_tree *n;
+ for (n = tree; n; n = n->left)
+ {
+ uint selected_idx;
+ do
+ {
+ selected_idx = bt_random() % nodes_count;
+ } while(avaible_indexes[selected_idx] != 0);
+
+ avaible_indexes[selected_idx] = 1;
+ n->from.type = n->to.type = T_INT;
+ n->from.val.i = n->to.val.i = selected_idx;
+ }
+
+ free(avaible_indexes);
+ return tree;
+}
+
+static struct f_tree *
+get_balanced_tree_with_ranged_values(uint nodes_count)
+{
+ struct f_tree *tree = get_degenerated_left_tree(nodes_count);
+
+ uint idx = 0;
+ struct f_tree *n;
+ for (n = tree; n; n = n->left)
+ {
+ n->from.type = n->to.type = T_INT;
+ n->from.val.i = idx;
+ idx += (uint)bt_random() / nodes_count; /* (... / nodes_count) preventing overflow an uint idx */
+ n->to.val.i = idx++;
+ }
+
+ return build_tree(tree);
+}
+
+
+static int
+t_balancing(void)
+{
+ start_conf_env();
+
+ uint height;
+ for (height = 1; height < MAX_TREE_HEIGHT; height++)
+ {
+ uint nodes_count = get_nodes_count_full_bin_tree(height);
+
+ struct f_tree *simple_degenerated_tree = get_degenerated_left_tree(nodes_count);
+ show_tree(simple_degenerated_tree);
+
+ struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
+ show_tree(expected_balanced_tree);
+
+ struct f_tree *balanced_tree_from_simple = build_tree(simple_degenerated_tree);
+ show_tree(balanced_tree_from_simple);
+
+ bt_assert(same_tree(balanced_tree_from_simple, expected_balanced_tree));
+ }
+
+ return BT_SUCCESS;
+}
+
+
+static int
+t_balancing_random(void)
+{
+ start_conf_env();
+
+ uint height;
+ for (height = 1; height < MAX_TREE_HEIGHT; height++)
+ {
+ uint nodes_count = get_nodes_count_full_bin_tree(height);
+
+ struct f_tree *expected_balanced_tree = get_balanced_full_tree(height);
+
+ uint i;
+ for(i = 0; i < 10; i++)
+ {
+ struct f_tree *random_degenerated_tree = get_random_degenerated_left_tree(nodes_count);
+ show_tree(random_degenerated_tree);
+
+ struct f_tree *balanced_tree_from_random = build_tree(random_degenerated_tree);
+
+ show_tree(expected_balanced_tree);
+ show_tree(balanced_tree_from_random);
+
+ bt_assert(same_tree(balanced_tree_from_random, expected_balanced_tree));
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_find(void)
+{
+ start_conf_env();
+
+ uint height;
+ for (height = 1; height < MAX_TREE_HEIGHT; height++)
+ {
+ uint nodes_count = get_nodes_count_full_bin_tree(height);
+
+ struct f_tree *tree = get_balanced_full_tree(height);
+ show_tree(tree);
+
+ struct f_val looking_up_value = {
+ .type = T_INT
+ };
+ for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++)
+ {
+ struct f_tree *found_tree = find_tree(tree, looking_up_value);
+ bt_assert((val_compare(looking_up_value, found_tree->from) == 0) && (val_compare(looking_up_value, found_tree->to) == 0));
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+static uint
+get_max_value_in_unbalanced_tree(struct f_tree *node, uint max)
+{
+ if (!node)
+ return max;
+
+ if (node->to.val.i > max)
+ max = node->to.val.i;
+
+ uint max_left = get_max_value_in_unbalanced_tree(node->left, max);
+ if (max_left > max)
+ max = max_left;
+
+ uint max_right = get_max_value_in_unbalanced_tree(node->right, max);
+ if (max_right > max)
+ max = max_right;
+
+ return max;
+}
+
+static int
+t_find_ranges(void)
+{
+ start_conf_env();
+
+ uint height;
+ for (height = 1; height < MAX_TREE_HEIGHT; height++)
+ {
+ uint nodes_count = get_nodes_count_full_bin_tree(height);
+
+ struct f_tree *tree = get_balanced_tree_with_ranged_values(nodes_count);
+ uint max_value = get_max_value_in_unbalanced_tree(tree, 0);
+
+ show_tree(tree);
+
+ bt_debug("max_value: %u \n", max_value);
+
+ struct f_val needle = {
+ .type = T_INT
+ };
+ uint *i = &needle.val.i;
+
+ for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count)
+ {
+ struct f_tree *found_tree = find_tree(tree, needle);
+ bt_debug("searching: %u \n", *i);
+ bt_assert(
+ (val_compare(needle, found_tree->from) == 0) || (val_compare(needle, found_tree->to) == 0) ||
+ ((val_compare(needle, found_tree->from) == 1) && (val_compare(needle, found_tree->to) == -1))
+ );
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_balancing, "Balancing strong unbalanced trees");
+ bt_test_suite(t_balancing_random, "Balancing random unbalanced trees");
+ bt_test_suite(t_find, "Finding values in trees");
+ bt_test_suite(t_find_ranges, "Finding values in trees with random ranged values");
+
+ return bt_exit_value();
+}
diff --git a/filter/trie_test.c b/filter/trie_test.c
new file mode 100644
index 00000000..c528c7d9
--- /dev/null
+++ b/filter/trie_test.c
@@ -0,0 +1,184 @@
+/*
+ * Filters: Utility Functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "filter/filter.h"
+#include "conf/conf.h"
+
+#define TESTS_NUM 10
+#define PREFIXES_NUM 10
+#define PREFIX_TESTS_NUM 10000
+
+#define BIG_BUFFER_SIZE 10000
+
+/* Wrapping structure for storing f_prefixes structures in list */
+struct f_prefix_node {
+ node n;
+ struct f_prefix prefix;
+};
+
+static u32
+xrandom(u32 max)
+{
+ return (bt_random() % max);
+}
+
+static int
+is_prefix_included(list *prefixes, struct f_prefix *needle)
+{
+ struct f_prefix_node *n;
+ WALK_LIST(n, *prefixes)
+ {
+ ip6_addr cmask = ip6_mkmask(MIN(n->prefix.net.pxlen, needle->net.pxlen));
+
+ ip6_addr ip = net6_prefix(&n->prefix.net);
+ ip6_addr needle_ip = net6_prefix(&needle->net);
+
+ if ((ipa_compare(ipa_and(ip, cmask), ipa_and(needle_ip, cmask)) == 0) &&
+ (n->prefix.lo <= needle->net.pxlen) && (needle->net.pxlen <= n->prefix.hi))
+ {
+ bt_debug("FOUND\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&n->prefix.net)), n->prefix.net.pxlen, n->prefix.lo, n->prefix.hi);
+ return 1; /* OK */
+ }
+ }
+ return 0; /* FAIL */
+}
+
+static struct f_prefix
+get_random_ip6_prefix(void)
+{
+ struct f_prefix p;
+ u8 pxlen = xrandom(120)+8;
+ ip6_addr ip6 = ip6_build(bt_random(),bt_random(),bt_random(),bt_random());
+ net_addr_ip6 net6 = NET_ADDR_IP6(ip6, pxlen);
+
+ p.net = *((net_addr*) &net6);
+
+ if (bt_random() % 2)
+ {
+ p.lo = 0;
+ p.hi = p.net.pxlen;
+ }
+ else
+ {
+ p.lo = p.net.pxlen;
+ p.hi = net_max_prefix_length[p.net.type];
+ }
+
+ return p;
+}
+
+static void
+generate_random_ipv6_prefixes(list *prefixes)
+{
+ int i;
+ for (i = 0; i < PREFIXES_NUM; i++)
+ {
+ struct f_prefix f = get_random_ip6_prefix();
+
+ struct f_prefix_node *px = calloc(1, sizeof(struct f_prefix_node));
+ px->prefix = f;
+
+ bt_debug("ADD\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&px->prefix.net)), px->prefix.net.pxlen, px->prefix.lo, px->prefix.hi);
+ add_tail(prefixes, &px->n);
+ }
+}
+
+static int
+t_match_net(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ uint round;
+ for (round = 0; round < TESTS_NUM; round++)
+ {
+ list prefixes; /* of structs f_extended_prefix */
+ init_list(&prefixes);
+ struct f_trie *trie = f_new_trie(config->mem, sizeof(struct f_trie_node));
+
+ generate_random_ipv6_prefixes(&prefixes);
+ struct f_prefix_node *n;
+ WALK_LIST(n, prefixes)
+ {
+ trie_add_prefix(trie, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ }
+
+ int i;
+ for (i = 0; i < PREFIX_TESTS_NUM; i++)
+ {
+ struct f_prefix f = get_random_ip6_prefix();
+ bt_debug("TEST\t" PRIip6 "/%d\n", ARGip6(net6_prefix(&f.net)), f.net.pxlen);
+
+ int should_be = is_prefix_included(&prefixes, &f);
+ int is_there = trie_match_net(trie, &f.net);
+ bt_assert_msg(should_be == is_there, "Prefix " PRIip6 "/%d %s", ARGip6(net6_prefix(&f.net)), f.net.pxlen, (should_be ? "should be found in trie" : "should not be found in trie"));
+ }
+
+ struct f_prefix_node *nxt;
+ WALK_LIST_DELSAFE(n, nxt, prefixes)
+ {
+ free(n);
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_trie_same(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ int round;
+ for (round = 0; round < TESTS_NUM*4; round++)
+ {
+ struct f_trie * trie1 = f_new_trie(config->mem, sizeof(struct f_trie_node));
+ struct f_trie * trie2 = f_new_trie(config->mem, sizeof(struct f_trie_node));
+
+ list prefixes; /* a list of f_extended_prefix structures */
+ init_list(&prefixes);
+ int i;
+ for (i = 0; i < 100; i++)
+ generate_random_ipv6_prefixes(&prefixes);
+
+ struct f_prefix_node *n;
+ WALK_LIST(n, prefixes)
+ {
+ trie_add_prefix(trie1, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ }
+ WALK_LIST_BACKWARDS(n, prefixes)
+ {
+ trie_add_prefix(trie2, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ }
+
+ bt_assert(trie_same(trie1, trie2));
+
+ struct f_prefix_node *nxt;
+ WALK_LIST_DELSAFE(n, nxt, prefixes)
+ {
+ free(n);
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_match_net, "Testing random prefix matching");
+ bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward.");
+
+ return bt_exit_value();
+}
diff --git a/lib/Makefile b/lib/Makefile
index 551089c3..26d8bf65 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,3 +1,7 @@
src := bitops.c checksum.c event.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)
+
+tests_src := heap_test.c buffer_test.c event_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c mac_test.c ip_test.c hash_test.c printf_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/lib/birdlib.h b/lib/birdlib.h
index ddc963f4..c352b7f6 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -56,7 +56,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define NULL ((void *) 0)
#endif
-
/* Macros for gcc attributes */
#define NORET __attribute__((noreturn))
@@ -150,7 +149,7 @@ void bug(const char *msg, ...) NORET;
#define L_FATAL "\010" /* Fatal errors */
#define L_BUG "\011" /* BIRD bugs */
-void debug(const char *msg, ...); /* Printf to debug output */
+void debug(const char *msg, ...); /* Printf to debug output */
/* Debugging */
diff --git a/lib/bitops.h b/lib/bitops.h
index 9f954374..af648c26 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -9,6 +9,8 @@
#ifndef _BIRD_BITOPTS_H_
#define _BIRD_BITOPTS_H_
+#include "sysdep/config.h"
+
/*
* Bit mask operations:
*
diff --git a/lib/bitops_test.c b/lib/bitops_test.c
new file mode 100644
index 00000000..bd02fccc
--- /dev/null
+++ b/lib/bitops_test.c
@@ -0,0 +1,123 @@
+/*
+ * BIRD Library -- Generic Bit Operations Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h" /* naive_pow() */
+
+#include "lib/bitops.h"
+
+#define MAX_NUM 1000
+#define CHECK_BIT(var,pos) ((var) & (u32)(1<<(pos)))
+
+static int
+t_mkmask(void)
+{
+ int i;
+ u32 compute, expect;
+
+ bt_assert(u32_mkmask(0) == 0x00000000);
+ for (i = 1; i <= 32; i++)
+ {
+ compute = u32_mkmask(i);
+ expect = (u32) (0xffffffff << (32-i));
+ bt_assert_msg(compute == expect, "u32_mkmask(%d) = 0x%08X, expected 0x%08X", i, compute, expect);
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+u32_masklen_expected(u32 mask)
+{
+ int j, expect = 0;
+
+ int valid = 0;
+ for (j = 0; j <= 32; j++)
+ if (mask == (j ? (0xffffffff << (32-j)) : 0)) /* Shifting 32-bit value by 32 bits is undefined behavior */
+ valid = 1;
+
+ if (!valid && mask != 0)
+ expect = 255;
+ else
+ for (j = 0; j <= 31; j++)
+ if (CHECK_BIT(mask, (31-j)))
+ expect = j+1;
+ else
+ break;
+ return expect;
+}
+
+static void
+check_mask(u32 mask)
+{
+ int expected, masklen;
+
+ expected = u32_masklen_expected(mask);
+ masklen = u32_masklen(mask);
+ int ok = (expected == masklen);
+ bt_debug("u32_masklen(Ox%08x) = %d, expected %d %s\n", mask, masklen, expected, ok ? "OK" : "FAIL!");
+ bt_assert(ok);
+}
+
+static int
+t_masklen(void)
+{
+ u32 i;
+
+ check_mask(0x82828282);
+ check_mask(0x00000000);
+
+ for (i = 0; i <= 32; i++)
+ check_mask(((u32) (i ? (0xffffffff << (32-i)) : 0)) & 0xffffffff); /* Shifting 32-bit value by 32 bits is undefined behavior */
+
+ for (i = 0; i <= MAX_NUM; i++)
+ check_mask(bt_random());
+
+ return BT_SUCCESS;
+}
+
+static void
+check_log2(u32 n)
+{
+ u32 log = u32_log2(n);
+ u32 low = bt_naive_pow(2, log);
+ u32 high = bt_naive_pow(2, log+1);
+
+ bt_assert_msg(n >= low && n < high,
+ "u32_log2(%u) = %u, %u should be in the range <%u, %u)",
+ n, log, n, low, high);
+}
+
+static int
+t_log2(void)
+{
+ u32 i;
+
+ for (i = 0; i < 31; i++)
+ bt_assert(u32_log2(bt_naive_pow(2, i+1)) == i+1);
+
+ for (i = 1; i < MAX_NUM; i++)
+ check_log2(i);
+
+ for (i = 1; i < MAX_NUM; i++)
+ check_log2(((u32) bt_random()) % 0x0fffffff);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_mkmask, "u32_mkmask()");
+ bt_test_suite(t_masklen, "u32_masklen()");
+ bt_test_suite(t_log2, "u32_log2()");
+
+ return bt_exit_value();
+}
diff --git a/lib/buffer_test.c b/lib/buffer_test.c
new file mode 100644
index 00000000..38e540b7
--- /dev/null
+++ b/lib/buffer_test.c
@@ -0,0 +1,147 @@
+/*
+ * BIRD Library -- Buffer Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+
+#include "test/birdtest.h"
+
+#include "lib/buffer.h"
+
+#define MAX_NUM 33
+
+typedef BUFFER(int) buffer_int;
+static int expected[MAX_NUM];
+static buffer_int buf;
+static struct pool *buffer_pool;
+
+static void
+show_buf(buffer_int *b)
+{
+ uint i;
+ bt_debug(".used = %d, .size = %d\n", b->used, b->size);
+
+ for (i = 0; i < b->used; i++)
+ bt_debug(" .data[%3u] = %-16d expected %-16d %s\n", i, b->data[i], expected[i], (b->data[i] == expected[i] ? "OK" : "FAIL!"));
+}
+
+static void
+fill_expected_array(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ expected[i] = bt_random();
+}
+
+static void
+init_buffer(void)
+{
+ resource_init();
+ buffer_pool = &root_pool;
+ BUFFER_INIT(buf, buffer_pool, MAX_NUM);
+}
+
+static int
+is_buffer_as_expected(buffer_int *b)
+{
+ show_buf(b);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(b->data[i] == expected[i]);
+ return 1;
+}
+
+static int
+t_buffer_push(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_buffer_pop(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+
+ /* POP a half of elements */
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ for (i = MAX_NUM-1; i >= MAX_NUM/2; i--)
+ BUFFER_POP(buf);
+ for (i = MAX_NUM/2; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i] = bt_random();
+ is_buffer_as_expected(&buf);
+
+ /* POP all of elements */
+ for (i = MAX_NUM-1; i >= 0; i--)
+ BUFFER_POP(buf);
+ bt_assert(buf.used == 0);
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_buffer_resize(void)
+{
+ int i;
+
+ init_buffer();
+ BUFFER_INIT(buf, buffer_pool, 0);
+ fill_expected_array();
+
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+ bt_assert(buf.size >= MAX_NUM);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_buffer_flush(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+
+ BUFFER_FLUSH(buf);
+ bt_assert(buf.used == 0);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_buffer_push, "Pushing new elements");
+ bt_test_suite(t_buffer_pop, "Fill whole buffer (PUSH), a half of elements POP and PUSH new elements");
+ bt_test_suite(t_buffer_resize, "Init a small buffer and try overfill");
+ bt_test_suite(t_buffer_flush, "Fill and flush all elements");
+
+ return bt_exit_value();
+}
diff --git a/lib/checksum_test.c b/lib/checksum_test.c
new file mode 100644
index 00000000..ae5a7f31
--- /dev/null
+++ b/lib/checksum_test.c
@@ -0,0 +1,94 @@
+/*
+ * BIRD Library -- IP One-Complement Checksum Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+
+#include "test/birdtest.h"
+
+#include "lib/checksum.h"
+
+#define MAX_NUM 10000
+
+static u16
+ipsum_calculate_expected(u32 *a)
+{
+ int i;
+ u32 sum = 0;
+
+ for(i = 0; i < MAX_NUM; i++)
+ {
+ sum += a[i] & 0xffff;
+ bt_debug("low) \t0x%08X \n", sum);
+
+ sum += a[i] >> 16;
+ bt_debug("high) \t0x%08X \n", sum);
+
+ u16 carry = sum >> 16;
+ sum = (sum & 0xffff) + carry;
+ bt_debug("carry) \t0x%08X \n\n", sum);
+ }
+ bt_debug("sum) \t0x%08X \n", sum);
+
+ sum = sum ^ 0xffff;
+ bt_debug("~sum) \t0x%08X \n", sum);
+
+ return sum;
+}
+
+static int
+t_calculate(void)
+{
+ u32 a[MAX_NUM];
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ a[i] = bt_random();
+
+ u16 sum_calculated = ipsum_calculate(a, sizeof(a), NULL);
+ u16 sum_calculated_2 = ipsum_calculate(&a[0], sizeof(u32)*(MAX_NUM/2), &a[MAX_NUM/2], sizeof(u32)*(MAX_NUM - MAX_NUM/2), NULL);
+ bt_assert(sum_calculated == sum_calculated_2);
+
+ u16 sum_expected = ipsum_calculate_expected(a);
+
+ bt_debug("sum_calculated: %08X \n", sum_calculated);
+ bt_debug("sum_expected: %08X \n", sum_expected);
+
+ bt_assert(sum_calculated == sum_expected);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_verify(void)
+{
+ u32 a[MAX_NUM+1];
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ a[i] = bt_random();
+
+ u16 sum = ipsum_calculate_expected(a);
+
+ a[MAX_NUM] = sum;
+
+ bt_assert(ipsum_verify(a, sizeof(a), NULL));
+
+ return BT_SUCCESS;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_calculate, "Checksum of pseudo-random data");
+ bt_test_suite(t_verify, "Verification of pseudo-random data.");
+
+ return bt_exit_value();
+}
diff --git a/lib/event_test.c b/lib/event_test.c
new file mode 100644
index 00000000..1997344d
--- /dev/null
+++ b/lib/event_test.c
@@ -0,0 +1,88 @@
+/*
+ * BIRD Library -- Event Processing Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include "test/birdtest.h"
+
+#include "lib/net.h"
+#include "lib/event.h"
+#include "conf/conf.h"
+#include "nest/locks.h"
+#include "sysdep/unix/unix.h"
+#include "nest/iface.h"
+#include "nest/route.h"
+
+#define MAX_NUM 4
+
+int event_check_points[MAX_NUM];
+
+#define event_hook_body(num) \
+ do { \
+ bt_debug("Event Hook " #num "\n"); \
+ event_check_points[num] = 1; \
+ bt_assert_msg(event_check_points[num-1], "Events should be run in right order"); \
+ } while (0)
+
+static void event_hook_1(void *data UNUSED) { event_hook_body(1); }
+static void event_hook_2(void *data UNUSED) { event_hook_body(2); }
+static void event_hook_3(void *data UNUSED) { event_hook_body(3); }
+
+#define schedule_event(num) \
+ do { \
+ struct event *event_##num = ev_new(&root_pool); \
+ event_##num->hook = event_hook_##num; \
+ ev_schedule(event_##num); \
+ } while (0)
+
+static void
+init_event_check_points(void)
+{
+ int i;
+ event_check_points[0] = 1;
+ for (i = 1; i < MAX_NUM; i++)
+ event_check_points[i] = 0;
+}
+
+static int
+t_ev_run_list(void)
+{
+ int i;
+
+ resource_init();
+ olock_init();
+ io_init();
+ rt_init();
+ if_init();
+// roa_init();
+ config_init();
+ config = config_alloc("");
+
+ init_event_check_points();
+
+ schedule_event(1);
+ schedule_event(2);
+ schedule_event(3);
+
+ ev_run_list(&global_event_list);
+
+ for (i = 1; i < MAX_NUM; i++)
+ bt_assert(event_check_points[i]);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_ev_run_list, "Schedule and run 3 events in right order.");
+
+ return bt_exit_value();
+}
+
diff --git a/lib/fletcher16_test.c b/lib/fletcher16_test.c
new file mode 100644
index 00000000..3e036900
--- /dev/null
+++ b/lib/fletcher16_test.c
@@ -0,0 +1,169 @@
+/*
+ * BIRD Library -- Fletcher-16 Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "lib/fletcher16.h"
+
+static u16
+straightforward_fletcher16_compute(const char *data)
+{
+ int count = strlen(data);
+
+ u16 sum1 = 0;
+ u16 sum2 = 0;
+ int index;
+
+ for (index = 0; index < count; ++index)
+ {
+ sum1 = (sum1 + data[index]) % 255;
+ sum2 = (sum2 + sum1) % 255;
+ }
+
+ return (sum2 << 8) | sum1;
+}
+
+static u16
+straightforward_fletcher16_checksum(const char *data)
+{
+ u16 csum;
+ u8 c0,c1,f0,f1;
+
+ csum = straightforward_fletcher16_compute(data);
+ f0 = csum & 0xff;
+ f1 = (csum >> 8) & 0xff;
+ c0 = 0xff - ((f0 + f1) % 0xff);
+ c1 = 0xff - ((f0 + c0) % 0xff);
+
+ return (c1 << 8) | c0;
+}
+
+static int
+test_fletcher16(void *out_, const void *in_, const void *expected_out_)
+{
+ u16 *out = out_;
+ const char *in = in_;
+ const u16 *expected_out = expected_out_;
+
+ struct fletcher16_context ctxt;
+
+ fletcher16_init(&ctxt);
+ fletcher16_update(&ctxt, in, strlen(in));
+ put_u16(out, fletcher16_compute(&ctxt));
+
+ return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
+}
+
+static int
+test_fletcher16_checksum(void *out_, const void *in_, const void *expected_out_)
+{
+ u16 *out = out_;
+ const char *in = in_;
+ const u16 *expected_out = expected_out_;
+
+ struct fletcher16_context ctxt;
+ int len = strlen(in);
+
+ fletcher16_init(&ctxt);
+ fletcher16_update(&ctxt, in, len);
+ put_u16(out, fletcher16_final(&ctxt, len, len));
+
+ return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
+}
+
+static int
+t_fletcher16_compute(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "\001\002",
+ .out = & (const u16) { 0x0403 },
+ },
+ {
+ .in = "",
+ .out = & ((const u16) { straightforward_fletcher16_compute("") }),
+ },
+ {
+ .in = "a",
+ .out = & ((const u16) { straightforward_fletcher16_compute("a") }),
+ },
+ {
+ .in = "abcd",
+ .out = & ((const u16) { straightforward_fletcher16_compute("abcd") }),
+ },
+ {
+ .in = "message digest",
+ .out = & ((const u16) { straightforward_fletcher16_compute("message digest") }),
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = & ((const u16) { straightforward_fletcher16_compute("abcdefghijklmnopqrstuvwxyz") }),
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = & ((const u16) { straightforward_fletcher16_compute("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = & ((const u16) { straightforward_fletcher16_compute("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_fletcher16, bt_fmt_str, bt_fmt_unsigned);
+}
+
+static int
+t_fletcher16_checksum(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "\001\002",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("\001\002") }),
+ },
+ {
+ .in = "",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("") }),
+ },
+ {
+ .in = "a",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("a") }),
+ },
+ {
+ .in = "abcd",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("abcd") }),
+ },
+ {
+ .in = "message digest",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("message digest") }),
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("abcdefghijklmnopqrstuvwxyz") }),
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_fletcher16_checksum, bt_fmt_str, bt_fmt_unsigned);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_fletcher16_compute, "Fletcher-16 Compute Tests");
+ bt_test_suite(t_fletcher16_checksum, "Fletcher-16 Checksum Tests");
+
+ return bt_exit_value();
+}
diff --git a/lib/hash_test.c b/lib/hash_test.c
new file mode 100644
index 00000000..07607f6e
--- /dev/null
+++ b/lib/hash_test.c
@@ -0,0 +1,305 @@
+/*
+ * BIRD Library -- Hash Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#undef LOCAL_DEBUG
+
+#include "test/birdtest.h"
+
+#include "lib/hash.h"
+
+struct test_node {
+ struct test_node *next; /* Hash chain */
+ u32 key;
+};
+
+#define TEST_KEY(n) n->key
+#define TEST_NEXT(n) n->next
+#define TEST_EQ(n1,n2) n1 == n2
+#define TEST_FN(n) (n) ^ u32_hash((n))
+#define TEST_ORDER 13
+#define TEST_PARAMS /TEST_ORDER, *2, 2, 2, TEST_ORDER, 20
+#define TEST_REHASH test_rehash
+
+HASH_DEFINE_REHASH_FN(TEST, struct test_node);
+
+HASH(struct test_node) hash;
+struct pool *my_pool;
+
+#define MAX_NUM (1 << TEST_ORDER)
+
+struct test_node nodes[MAX_NUM];
+
+static void
+print_rate_of_fulfilment(void)
+{
+ int i;
+ int num_stacked_items = 0;
+
+ for (i = 0; i < MAX_NUM; i++)
+ if (!hash.data[i])
+ num_stacked_items++;
+
+ double percent_stacked_items = ((double)num_stacked_items/(double)MAX_NUM)*100.;
+ bt_debug("%d (%.2f %%) chained of %d hashes \n", num_stacked_items, percent_stacked_items, MAX_NUM);
+}
+
+#ifdef LOCAL_DEBUG
+static void
+dump_nodes(void)
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_debug("nodes[%3d] is at address %14p has .key %3d, .next %14p \n", i, &nodes[i], nodes[i].key, nodes[i].next);
+}
+#endif
+
+static void
+init_hash_(uint order)
+{
+ resource_init();
+ my_pool = rp_new(&root_pool, "Test pool");
+
+ HASH_INIT(hash, my_pool, order);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ nodes[i].next = NULL;
+ }
+
+ bt_debug("MAX_NUM %d \n", MAX_NUM);
+}
+
+static void
+init_hash(void)
+{
+ init_hash_(TEST_ORDER);
+}
+
+static void
+validate_filled_hash(void)
+{
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ node = HASH_FIND(hash, TEST, nodes[i].key);
+ bt_assert_msg(node->key == nodes[i].key, "Hash should be filled, to find (%p) the node[%d] (%p) with .key = %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
+ }
+
+ print_rate_of_fulfilment();
+}
+
+static void
+validate_empty_hash(void)
+{
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ node = HASH_FIND(hash, TEST, nodes[i].key);
+ bt_assert_msg(node == NULL, "Hash should be empty, to find (%p) the node[%d] (%p) with .key %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
+ }
+}
+
+static void
+fill_hash(void)
+{
+ int i;
+ struct test_node *node;
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ node = &nodes[i];
+ HASH_INSERT(hash, TEST, node);
+ }
+}
+
+static int
+t_insert_find(void)
+{
+ init_hash();
+ fill_hash();
+ validate_filled_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_insert_find_random(void)
+{
+ init_hash();
+
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = bt_random();
+ node = &nodes[i];
+ HASH_INSERT(hash, TEST, node);
+ }
+
+ validate_filled_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_insert2_find(void)
+{
+ init_hash_(1);
+
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ node = &nodes[i];
+ HASH_INSERT2(hash, TEST, my_pool, node);
+ }
+ bt_assert_msg(hash.order != 1, "The hash should auto-resize from order 2^1. The order of the hash is 2^%u.", hash.order);
+
+ validate_filled_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk(void)
+{
+ init_hash();
+ fill_hash();
+
+ uint i;
+ uint check[MAX_NUM];
+ for (i = 0; i < MAX_NUM; i++)
+ check[i] = 0;
+
+ HASH_WALK(hash, next, n)
+ {
+ check[n->key]++;
+ }
+ HASH_WALK_END;
+
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(check[i] == 1);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk_delsafe_delete(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_DELETE(hash, TEST, n->key);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk_delsafe_remove(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_REMOVE(hash, TEST, n);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk_delsafe_delete2(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_DELETE2(hash, TEST, my_pool, n->key);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk_delsafe_remove2(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_REMOVE2(hash, TEST, my_pool, n);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return BT_SUCCESS;
+}
+
+static int
+t_walk_filter(void)
+{
+ init_hash();
+ fill_hash();
+
+ uint i;
+ uint check[MAX_NUM];
+ for (i = 0; i < MAX_NUM; i++)
+ check[i] = 0;
+
+ HASH_WALK_FILTER(hash, next, n, m)
+ {
+ bt_assert(n == *m);
+ check[n->key]++;
+ }
+ HASH_WALK_FILTER_END;
+
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(check[i] == 1);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_insert_find, "HASH_INSERT and HASH_FIND");
+ bt_test_suite(t_insert_find_random, "HASH_INSERT pseudo-random keys and HASH_FIND");
+ bt_test_suite(t_insert2_find, "HASH_INSERT2 and HASH_FIND. HASH_INSERT2 is HASH_INSERT and a smart auto-resize function");
+ bt_test_suite(t_walk, "HASH_WALK");
+ bt_test_suite(t_walk_delsafe_delete, "HASH_WALK_DELSAFE and HASH_DELETE");
+ bt_test_suite(t_walk_delsafe_delete2, "HASH_WALK_DELSAFE and HASH_DELETE2. HASH_DELETE2 is HASH_DELETE and smart auto-resize function");
+ bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
+ bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
+ bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
+
+ return bt_exit_value();
+}
diff --git a/lib/heap_test.c b/lib/heap_test.c
new file mode 100644
index 00000000..40c9dd83
--- /dev/null
+++ b/lib/heap_test.c
@@ -0,0 +1,186 @@
+/*
+ * BIRD Library -- Universal Heap Macros Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "sysdep/config.h"
+#include "lib/heap.h"
+
+#define MAX_NUM 1000
+#define SPECIAL_KEY -3213
+
+#define MY_CMP(x, y) ((x) < (y))
+
+#define MY_HEAP_SWAP(heap,a,b,t) \
+ do { \
+ bt_debug("swap(%u %u) ", a, b); \
+ HEAP_SWAP(heap,a,b,t); \
+ } while(0)
+
+static int heap[MAX_NUM+1];
+static uint num;
+
+/*
+ * A valid heap must follow these rules:
+ * - `num >= 0`
+ * - `heap[i] >= heap[i / 2]` for each `i` in `[2, num]`
+ */
+static int
+is_heap_valid(int heap[], uint num)
+{
+ uint i;
+
+ if (num > MAX_NUM)
+ return 0;
+
+ for (i = 2; i <= num; i++)
+ if (heap[i] < heap[i / 2])
+ return 0;
+
+ return 1;
+}
+
+static void
+show_heap(void)
+{
+ uint i;
+ bt_debug("\n");
+ bt_debug("numbers %u; ", num);
+ for (i = 0; i <= num; i++)
+ bt_debug("%d ", heap[i]);
+ bt_debug(is_heap_valid(heap, num) ? "OK" : "NON-VALID HEAP!");
+ bt_debug("\n");
+}
+
+static void
+init_heap(void)
+{
+ uint i;
+ num = 0;
+ heap[0] = SPECIAL_KEY; /* heap[0] should be unused */
+ for (i = 1; i <= MAX_NUM; i++)
+ heap[i] = 0;
+}
+
+static int
+t_heap_insert(void)
+{
+ uint i;
+
+ init_heap();
+
+ for (i = MAX_NUM; i >= 1; i--)
+ {
+ bt_debug("ins %u at pos %u ", i, MAX_NUM - i);
+ heap[MAX_NUM - i + 1] = i;
+ HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_heap_increase_decrease(void)
+{
+ uint i;
+
+ t_heap_insert();
+
+ for (i = 1; i <= MAX_NUM; i++)
+ {
+ if ((int)i > heap[i])
+ {
+ bt_debug("inc %u ", i);
+ heap[i] = i;
+ HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ }
+ else if ((int)i < heap[i])
+ {
+ bt_debug("dec %u ", i);
+ heap[i] = i;
+ HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ }
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_heap_delete(void)
+{
+ uint i;
+
+ t_heap_insert();
+
+ for (i = 1; i <= num; i++)
+ {
+ bt_debug("del at pos %u ", i);
+ HEAP_DELETE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_heap_0(void)
+{
+ init_heap();
+ t_heap_insert();
+ t_heap_increase_decrease();
+ t_heap_delete();
+
+ return (heap[0] == SPECIAL_KEY) ? BT_SUCCESS : BT_FAILURE;
+}
+
+static int
+t_heap_insert_random(void)
+{
+ int i, j;
+ int expected[MAX_NUM+1];
+
+ init_heap();
+
+ for (i = 1; i <= MAX_NUM; i++)
+ {
+ heap[i] = expected[i] = bt_random();
+ HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ for (i = 1; i <= MAX_NUM; i++)
+ for (j = 1; j <= MAX_NUM; j++)
+ if(expected[i] == heap[j])
+ break;
+ else if (j == MAX_NUM)
+ {
+ show_heap();
+ bt_abort_msg("Did not find a number %d in heap.", expected[i]);
+ }
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_heap_insert, "Inserting a descending sequence of numbers (the worst case)");
+ bt_test_suite(t_heap_insert_random, "Inserting pseudo-random numbers");
+ bt_test_suite(t_heap_increase_decrease, "Increasing/Decreasing");
+ bt_test_suite(t_heap_delete, "Deleting");
+ bt_test_suite(t_heap_0, "Is a heap[0] really unused?");
+
+ return bt_exit_value();
+}
diff --git a/lib/ip.c b/lib/ip.c
index 5e039c12..9497248c 100644
--- a/lib/ip.c
+++ b/lib/ip.c
@@ -306,7 +306,7 @@ ip6_pton(const char *a, ip6_addr *o)
if (*a == ':' && a[1])
a++;
- else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
+ else if (*a == '.' && (i == 6 || (i < 6 && hfil >= 0)))
{ /* Embedded IPv4 address */
ip4_addr x;
if (!ip4_pton(start, &x))
diff --git a/lib/ip_test.c b/lib/ip_test.c
new file mode 100644
index 00000000..81b4897e
--- /dev/null
+++ b/lib/ip_test.c
@@ -0,0 +1,161 @@
+/*
+ * BIRD Library -- IP address functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/ip.h"
+
+#define IP4_MAX_LEN 16
+
+static int
+test_ipa_pton(void *out_, const void *in_, const void *expected_out_)
+{
+ ip_addr *out = out_;
+ const char *in = in_;
+ const ip_addr *expected_out = expected_out_;
+
+ if (ipa_is_ip4(*expected_out))
+ {
+ ip4_addr ip4;
+ bt_assert(ip4_pton(in, &ip4));
+ *out = ipa_from_ip4(ip4);
+ }
+ else
+ {
+ bt_assert(ip6_pton(in, out));
+ /* ip_addr == ip6_addr */
+ }
+
+ return ipa_equal(*out, *expected_out) ? BT_SUCCESS : BT_FAILURE;
+}
+
+static int
+t_ip4_pton(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "192.168.1.128",
+ .out = & ipa_build4(192, 168, 1, 128),
+ },
+ {
+ .in = "255.255.255.255",
+ .out = & ipa_build4(255, 255, 255, 255),
+ },
+ {
+ .in = "0.0.0.0",
+ .out = & ipa_build4(0, 0, 0, 0),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+}
+
+static int
+t_ip6_pton(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "2001:0db8:0000:0000:0000:0000:1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:0db8:0000:0000:0000::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:0db8::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:db8::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "::1",
+ .out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000001),
+ },
+ {
+ .in = "::",
+ .out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000000),
+ },
+ {
+ .in = "2605:2700:0:3::4713:93e3",
+ .out = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+}
+
+static int
+test_ipa_ntop(void *out_, const void *in_, const void *expected_out_)
+{
+ char *out = out_;
+ const ip_addr *in = in_;
+ const char *expected_out = expected_out_;
+
+ if (ipa_is_ip4(*in))
+ ip4_ntop(ipa_to_ip4(*in), out);
+ else
+ ip6_ntop(ipa_to_ip6(*in), out);
+
+ int result = strncmp(out, expected_out, ipa_is_ip4(*in) ? IP4_MAX_TEXT_LENGTH : IP6_MAX_TEXT_LENGTH) == 0;
+ return result ? BT_SUCCESS : BT_FAILURE;
+}
+
+static int
+t_ip4_ntop(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & ipa_build4(192, 168, 1, 128),
+ .out = "192.168.1.128",
+ },
+ {
+ .in = & ipa_build4(255, 255, 255, 255),
+ .out = "255.255.255.255",
+ },
+ {
+ .in = & ipa_build4(0, 0, 0, 1),
+ .out = "0.0.0.1",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
+}
+
+static int
+t_ip6_ntop(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ .out = "2001:db8::1428:57ab",
+ },
+ {
+ .in = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
+ .out = "2605:2700:0:3::4713:93e3",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_ip4_pton, "Converting IPv4 string to ip4_addr struct");
+ bt_test_suite(t_ip6_pton, "Converting IPv6 string to ip6_addr struct");
+ bt_test_suite(t_ip4_ntop, "Converting ip4_addr struct to IPv4 string");
+ bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
+
+ return bt_exit_value();
+}
+
diff --git a/lib/lists_test.c b/lib/lists_test.c
new file mode 100644
index 00000000..56cc8427
--- /dev/null
+++ b/lib/lists_test.c
@@ -0,0 +1,287 @@
+/*
+ * BIRD Library -- Linked Lists Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "lib/lists.h"
+
+#define MAX_NUM 1000
+
+static node nodes[MAX_NUM];
+static list l;
+
+static void
+show_list(void)
+{
+ bt_debug("\n");
+ bt_debug("list.null is at %p and point to %p\n", &l.null, l.null);
+ bt_debug("list.head is at %p and point to %p\n", &l.head, l.head);
+ bt_debug("list.tail is at %p and point to %p\n", &l.tail, l.tail);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ bt_debug("n[%3i] is at %p\n", i, &nodes[i]);
+ bt_debug(" prev is at %p and point to %p\n", &(nodes[i].prev), nodes[i].prev);
+ bt_debug(" next is at %p and point to %p\n", &(nodes[i].next), nodes[i].next);
+ }
+}
+
+static int
+is_filled_list_well_linked(void)
+{
+ int i;
+ bt_assert(l.head == &nodes[0]);
+ bt_assert(l.tail == &nodes[MAX_NUM-1]);
+ bt_assert((void *) nodes[0].prev == (void *) &l.head);
+ bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &l.null);
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ if (i < (MAX_NUM-1))
+ bt_assert(nodes[i].next == &nodes[i+1]);
+
+ if (i > 0)
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+
+ return 1;
+}
+
+static int
+is_empty_list_well_unlinked(void)
+{
+ int i;
+
+ bt_assert(l.head == NODE &l.null);
+ bt_assert(l.tail == NODE &l.head);
+ bt_assert(EMPTY_LIST(l));
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ bt_assert(nodes[i].next == NULL);
+ bt_assert(nodes[i].prev == NULL);
+ }
+
+ return 1;
+}
+
+static void
+init_list__(list *l, struct node nodes[])
+{
+ init_list(l);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].next = NULL;
+ nodes[i].prev = NULL;
+ }
+}
+
+static void
+init_list_(void)
+{
+ init_list__(&l, (node *) nodes);
+}
+
+static int
+t_add_tail(void)
+{
+ int i;
+
+ init_list_();
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ add_tail(&l, &nodes[i]);
+ bt_debug(".");
+ bt_assert(l.tail == &nodes[i]);
+ bt_assert(l.head == &nodes[0]);
+ bt_assert((void *) nodes[i].next == (void *) &l.null);
+ if (i > 0)
+ {
+ bt_assert(nodes[i-1].next == &nodes[i]);
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+ }
+ show_list();
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static int
+t_add_head(void)
+{
+ int i;
+
+ init_list_();
+ for (i = MAX_NUM-1; i >= 0; i--)
+ {
+ add_head(&l, &nodes[i]);
+ bt_debug(".");
+ bt_assert(l.head == &nodes[i]);
+ bt_assert(l.tail == &nodes[MAX_NUM-1]);
+ if (i < MAX_NUM-1)
+ {
+ bt_assert(nodes[i+1].prev == &nodes[i]);
+ bt_assert(nodes[i].next == &nodes[i+1]);
+ }
+ }
+ show_list();
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static void
+insert_node_(node *n, node *after)
+{
+ insert_node(n, after);
+ bt_debug(".");
+}
+
+static int
+t_insert_node(void)
+{
+ int i;
+
+ init_list_();
+
+ // add first node
+ insert_node_(&nodes[0], NODE &l.head);
+
+ // add odd nodes
+ for (i = 2; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-2]);
+
+ // add even nodes
+ for (i = 1; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-1]);
+
+ bt_debug("\n");
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static void
+fill_list2(list *l, node nodes[])
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ add_tail(l, &nodes[i]);
+}
+
+static void
+fill_list(void)
+{
+ fill_list2(&l, (node *) nodes);
+}
+
+static int
+t_remove_node(void)
+{
+ int i;
+
+ init_list_();
+
+ /* Fill & Remove & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i++)
+ rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ /* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i+=2)
+ rem_node(&nodes[i]);
+
+ int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
+ bt_assert(l.head == &nodes[1]);
+ bt_assert(l.tail == &nodes[tail_node_index]);
+ bt_assert(nodes[tail_node_index].next == NODE &l.null);
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ {
+ if (i > 1)
+ bt_assert(nodes[i].prev == &nodes[i-2]);
+ if (i < tail_node_index)
+ bt_assert(nodes[i].next == &nodes[i+2]);
+ }
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ return BT_SUCCESS;
+}
+
+static int
+t_replace_node(void)
+{
+ node head, inside, tail;
+
+ init_list_();
+ fill_list();
+
+ replace_node(&nodes[0], &head);
+ bt_assert(l.head == &head);
+ bt_assert(head.prev == NODE &l.head);
+ bt_assert(head.next == &nodes[1]);
+ bt_assert(nodes[1].prev == &head);
+
+ replace_node(&nodes[MAX_NUM/2], &inside);
+ bt_assert(nodes[MAX_NUM/2-1].next == &inside);
+ bt_assert(nodes[MAX_NUM/2+1].prev == &inside);
+ bt_assert(inside.prev == &nodes[MAX_NUM/2-1]);
+ bt_assert(inside.next == &nodes[MAX_NUM/2+1]);
+
+ replace_node(&nodes[MAX_NUM-1], &tail);
+ bt_assert(l.tail == &tail);
+ bt_assert(tail.prev == &nodes[MAX_NUM-2]);
+ bt_assert(tail.next == NODE &l.null);
+ bt_assert(nodes[MAX_NUM-2].next == &tail);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_add_tail_list(void)
+{
+ node nodes2[MAX_NUM];
+ list l2;
+
+ init_list__(&l, (node *) nodes);
+ fill_list2(&l, (node *) nodes);
+
+ init_list__(&l2, (node *) nodes2);
+ fill_list2(&l2, (node *) nodes2);
+
+ add_tail_list(&l, &l2);
+
+ bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
+ bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
+ bt_assert(l.tail == &nodes2[MAX_NUM-1]);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_add_tail, "Adding nodes to tail of list");
+ bt_test_suite(t_add_head, "Adding nodes to head of list");
+ bt_test_suite(t_insert_node, "Inserting nodes to list");
+ bt_test_suite(t_remove_node, "Removing nodes from list");
+ bt_test_suite(t_replace_node, "Replacing nodes in list");
+ bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
+
+ return bt_exit_value();
+}
diff --git a/lib/mac_test.c b/lib/mac_test.c
new file mode 100644
index 00000000..8522f95e
--- /dev/null
+++ b/lib/mac_test.c
@@ -0,0 +1,1159 @@
+/*
+ * BIRD Library -- SHA and HMAC-SHA functions tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "lib/mac.h"
+
+
+#define define_test_hash_fn(name,id) \
+static int \
+test_##name(void *out_, const void *in_, const void *expected_out_) \
+{ \
+ char *out = out_; \
+ const char *in = in_; \
+ const char *expected_out = expected_out_; \
+ \
+ struct mac_context ctx; \
+ mac_init(&ctx, id, NULL, 0); \
+ mac_update(&ctx, in, strlen(in)); \
+ byte *out_bin = mac_final(&ctx); \
+ \
+ uint len = mac_type_length(id); \
+ bt_bytes_to_hex(out, out_bin, len); \
+ \
+ return strncmp(out, expected_out, 2*len+1) == 0 ? BT_SUCCESS : BT_FAILURE; \
+}
+
+define_test_hash_fn(md5, ALG_MD5)
+define_test_hash_fn(sha1, ALG_SHA1)
+define_test_hash_fn(sha224, ALG_SHA224)
+define_test_hash_fn(sha256, ALG_SHA256)
+define_test_hash_fn(sha384, ALG_SHA384)
+define_test_hash_fn(sha512, ALG_SHA512)
+
+
+static int
+t_md5(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "d41d8cd98f00b204e9800998ecf8427e",
+ },
+ {
+ .in = "a",
+ .out = "0cc175b9c0f1b6a831c399e269772661",
+ },
+ {
+ .in = "abc",
+ .out = "900150983cd24fb0d6963f7d28e17f72",
+ },
+ {
+ .in = "message digest",
+ .out = "f96b697d7cb7938d525a2f31aaf161d0",
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = "c3fcd3d76192e4007dfb496cca67e13b",
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = "d174ab98d277d9f5a5611c2c9f419d9f",
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = "57edf4a22be3c955ac49da2e2107b67a",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_md5, bt_fmt_str, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx functions
+ */
+
+
+static int
+t_sha1(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ },
+ {
+ .in = "a",
+ .out = "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
+ },
+ {
+ .in = "abc",
+ .out = "a9993e364706816aba3e25717850c26c9cd0d89d",
+ },
+ {
+ .in = "message digest",
+ .out = "c12252ceda8be8994d5fa0290a47231c1d16aae3",
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = "32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = "761c457bf73b14d27e9e9265c46f4b4dda11f940",
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = "50abf5706a150990a08b2c5ea40fa0e585554732",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "6a64fcc1fb970f7339ce886601775d2efea5cd4b",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha1, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha224(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
+ },
+ {
+ .in = "a",
+ .out = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5",
+ },
+ {
+ .in = "abc",
+ .out = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "cca7dd1a332a17775d8b0429bdb45055c2d4368ebaab0c7cf385586e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha224, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha256(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ },
+ {
+ .in = "a",
+ .out = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
+ },
+ {
+ .in = "abc",
+ .out = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "bf18b43b61652b5d73f41ebf3d72e5e43aebf5076f497dde31ea3de9de4998ef",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha256, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha384(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+ },
+ {
+ .in = "a",
+ .out = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
+ },
+ {
+ .in = "abc",
+ .out = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "6452928a62ca915a60f2d16ea22cc832d8ecb35443d78a3ff6986e7def9174a1dc16ce2ff65d3ed1666db98357f3c05e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha384, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha512(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+ },
+ {
+ .in = "a",
+ .out = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+ },
+ {
+ .in = "abc",
+ .out = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "415509a1c345371acb3e27a88b3835e3b6dfebcbbab5134850596f4db64d7bb22ac42c3cd179446a80c92b8be955460eb536eac01389a7e1fdf09d1dca83922f",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha512, bt_fmt_str, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx HMAC functions
+ */
+
+#define HMAC_BUFFER_SIZE 160
+struct hmac_data_in {
+ byte key[HMAC_BUFFER_SIZE];
+ uint key_len;
+ byte data[HMAC_BUFFER_SIZE];
+ uint data_len;
+};
+
+static void
+hmac_in_fmt(char *buf, size_t size, const void *data_)
+{
+ uint i;
+ const struct hmac_data_in *data = data_;
+
+ snprintf(buf, size, "data: '");
+ for (i = 0; i < data->data_len; i++)
+ snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(data->data[i]) ? "%c" : " 0x%02x", data->data[i]);
+
+ snprintf(buf+strlen(buf), size-strlen(buf), "', key: '");
+ for (i = 0; i < data->key_len; i++)
+ snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(data->key[i]) ? "%c" : " 0x%02x", data->key[i]);
+ snprintf(buf+strlen(buf), size-strlen(buf), "'");
+}
+
+#define define_test_hmac_fn(name,id) \
+static int \
+test_##name##_hmac(void *out_, const void *in_, const void *expected_out_) \
+{ \
+ char *out = out_; \
+ const struct hmac_data_in *in = in_; \
+ const char *expected_out = expected_out_; \
+ \
+ struct mac_context ctx; \
+ mac_init(&ctx, id, in->key, in->key_len); \
+ mac_update(&ctx, in->data, in->data_len); \
+ byte *out_bin = mac_final(&ctx); \
+ \
+ uint len = mac_type_length(id); \
+ bt_bytes_to_hex(out, out_bin, len); \
+ \
+ return strncmp(out, expected_out, 2*len+1) == 0 ? BT_SUCCESS : BT_FAILURE; \
+}
+
+define_test_hmac_fn(md5, ALG_HMAC_MD5)
+define_test_hmac_fn(sha1, ALG_HMAC_SHA1)
+define_test_hmac_fn(sha224, ALG_HMAC_SHA224)
+define_test_hmac_fn(sha256, ALG_HMAC_SHA256)
+define_test_hmac_fn(sha384, ALG_HMAC_SHA384)
+define_test_hmac_fn(sha512, ALG_HMAC_SHA512)
+
+
+static int
+t_md5_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 16,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "9294727a3638bb1c13f48ef8158bfc9d",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "750c783e6ab0b503eaa86e310a5db738",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 16,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "56be34521d144c88dbb8c733f0e8b3f6",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "697eaf0aca3a3aea3a75164746ffaa79",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 16,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "56461ef2342edc00f9bab995690efd4c",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ .data_len = 73,
+ },
+ .out = "6f630fad67cda0ee1fb1f562db3aa53e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_md5_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha1_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "b617318655057264e28bc0b6fb378c8ef146be00",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "125d7342b9ac11cd91a39af48aa17b4f63f175d3",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "4c9007f4026250c6bc8414f9bf50c86c2d7235da",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "aa4ae5e15272d00e95705637ce8a3b55ed402112",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ .data_len = 73,
+ },
+ .out = "e8e99d0f45237d786d6bbaa7965c7808bbff1a91",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61,
+ },
+ .key_len = 64,
+ .data = "Test Using key 64 bytes sized",
+ .data_len = 29,
+ },
+ .out = "a55d4fb80962a6b3d2e720705314bee417d68cf6",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha1_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha224_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha224_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha256_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha256_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha384_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha384_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha512_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha512_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx concating independence
+ */
+
+#include "lib/sha256.h"
+#include "lib/sha512.h"
+
+static int
+t_sha256_concating(void)
+{
+ char hash_a[SHA256_HEX_SIZE];
+ char hash_b[SHA256_HEX_SIZE];
+
+ char *str_a = "a" "bb" "ccc" "dddd" "eeeee" "ffffff";
+ char *str_b1 = "a" ;
+ char *str_b2 = "bb" ;
+ char *str_b3 = "ccc" ;
+ char *str_b4 = "dddd" ;
+ char *str_b5 = "eeeee" ;
+ char *str_b6 = "ffffff";
+
+ struct hash_context ctx_a;
+ sha256_init(&ctx_a);
+ sha256_update(&ctx_a, str_a, strlen(str_a));
+ byte *hash_a_ = sha256_final(&ctx_a);
+ bt_bytes_to_hex(hash_a, hash_a_, SHA256_SIZE);
+
+ struct hash_context ctx_b;
+ sha256_init(&ctx_b);
+ sha256_update(&ctx_b, str_b1, strlen(str_b1));
+ sha256_update(&ctx_b, str_b2, strlen(str_b2));
+ sha256_update(&ctx_b, str_b3, strlen(str_b3));
+ sha256_update(&ctx_b, str_b4, strlen(str_b4));
+ sha256_update(&ctx_b, str_b5, strlen(str_b5));
+ sha256_update(&ctx_b, str_b6, strlen(str_b6));
+ byte *hash_b_ = sha256_final(&ctx_b);
+ bt_bytes_to_hex(hash_b, hash_b_, SHA256_SIZE);
+
+ int are_hash_a_b_equal = (strncmp(hash_a, hash_b, sizeof(hash_a)) == 0);
+ bt_assert_msg(are_hash_a_b_equal, "Hashes A: %s, B: %s should be same", hash_a, hash_b);
+
+ return BT_SUCCESS;
+}
+
+
+static int
+t_sha512_concating(void)
+{
+ char hash_a[SHA512_HEX_SIZE];
+ char hash_b[SHA512_HEX_SIZE];
+
+ char *str_a = "a" "bb" "ccc" "dddd" "eeeee" "ffffff";
+ char *str_b1 = "a" ;
+ char *str_b2 = "bb" ;
+ char *str_b3 = "ccc" ;
+ char *str_b4 = "dddd" ;
+ char *str_b5 = "eeeee" ;
+ char *str_b6 = "ffffff";
+
+ struct hash_context ctx_a;
+ sha512_init(&ctx_a);
+ sha512_update(&ctx_a, str_a, strlen(str_a));
+ byte *hash_a_ = sha512_final(&ctx_a);
+ bt_bytes_to_hex(hash_a, hash_a_, SHA512_SIZE);
+
+ struct hash_context ctx_b;
+ sha512_init(&ctx_b);
+ sha512_update(&ctx_b, str_b1, strlen(str_b1));
+ sha512_update(&ctx_b, str_b2, strlen(str_b2));
+ sha512_update(&ctx_b, str_b3, strlen(str_b3));
+ sha512_update(&ctx_b, str_b4, strlen(str_b4));
+ sha512_update(&ctx_b, str_b5, strlen(str_b5));
+ sha512_update(&ctx_b, str_b6, strlen(str_b6));
+ byte *hash_b_ = sha512_final(&ctx_b);
+ bt_bytes_to_hex(hash_b, hash_b_, SHA512_SIZE);
+
+ int are_hash_a_b_equal = (strncmp(hash_a, hash_b, sizeof(hash_a)) == 0);
+ bt_assert_msg(are_hash_a_b_equal, "Hashes A: %s, B: %s should be same", hash_a, hash_b);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_md5, "Testing MD5 by RFC 1321");
+ bt_test_suite(t_sha1, "Testing SHA-1");
+ bt_test_suite(t_sha224, "Testing SHA-224");
+ bt_test_suite(t_sha256, "Testing SHA-256");
+ bt_test_suite(t_sha384, "Testing SHA-384");
+ bt_test_suite(t_sha512, "Testing SHA-512");
+
+ bt_test_suite(t_md5_hmac, "Testing HMAC-MD5 by RFC 2202");
+ bt_test_suite(t_sha1_hmac, "Testing HMAC-SHA-1 by RFC 2202");
+ bt_test_suite(t_sha224_hmac, "Testing HMAC-SHA-224 by RFC 4231");
+ bt_test_suite(t_sha256_hmac, "Testing HMAC-SHA-256 by RFC 4231");
+ bt_test_suite(t_sha384_hmac, "Testing HMAC-SHA-384 by RFC 4231");
+ bt_test_suite(t_sha512_hmac, "Testing HMAC-SHA-512 by RFC 4231");
+
+ bt_test_suite(t_sha256_concating, "Testing concatenation input string to hash using sha256_update");
+ bt_test_suite(t_sha512_concating, "Testing concatenation input string to hash using sha512_update");
+
+ return bt_exit_value();
+}
diff --git a/lib/patmatch_test.c b/lib/patmatch_test.c
new file mode 100644
index 00000000..b2b4cb92
--- /dev/null
+++ b/lib/patmatch_test.c
@@ -0,0 +1,149 @@
+/*
+ * BIRD Library -- Pattern Matching Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "nest/bird.h"
+#include "lib/string.h"
+
+#define MATCH (int) { 1 }
+#define NOMATCH (int) { 0 }
+
+struct match_pair {
+ byte *pattern;
+ byte *data;
+};
+
+static int
+test_matching(void *out_, const void *in_, const void *expected_out_)
+{
+ int *out = out_;
+ const struct match_pair *in = in_;
+ const int *expected_out = expected_out_;
+
+ *out = patmatch(in->pattern, in->data);
+
+ return (*out == *expected_out) ? BT_SUCCESS : BT_FAILURE;
+}
+
+static void
+fmt_match_pair(char *buf, size_t size, const void *data)
+{
+ const struct match_pair *mp = data;
+ snprintf(buf, size, "pattern: '%s', subject: '%s'", mp->pattern, mp->data);
+}
+
+static void
+fmt_match_result(char *buf, size_t size, const void *data)
+{
+ const int *result = data;
+ snprintf(buf, size, *result ? "match" : "no-match");
+}
+
+static int
+t_matching(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct match_pair) {
+ .pattern = "",
+ .data = "",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "*",
+ .data = "",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "\\*",
+ .data = "*",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "\\*",
+ .data = "a",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "?",
+ .data = "",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqrstuvwxyz",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "??????????????????????????",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "*abcdefghijklmnopqrstuvwxyz*",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "ab?defg*jklmnop*stu*wxy*z",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqrstuvwxyz",
+ .data = "abcdefghijklmnopqrtuvwxyz",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqr?uvwxyz",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "aa*aaaaa?aaaaaaaaaaaaaaaaaaa",
+ .data = "aaaaaaaaaaaaaaaaaaaaaaaaaa",
+ },
+ .out = & NOMATCH,
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_matching, fmt_match_pair, fmt_match_result);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_matching, "Pattern matching");
+
+ return bt_exit_value();
+}
diff --git a/lib/printf_test.c b/lib/printf_test.c
new file mode 100644
index 00000000..9763b7b1
--- /dev/null
+++ b/lib/printf_test.c
@@ -0,0 +1,70 @@
+/*
+ * BIRD Library -- String Functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/string.h"
+
+#define BSPRINTF(nw, res, buf, fmt, ...) \
+ do { \
+ int n = bsprintf(buf, fmt, ##__VA_ARGS__); \
+ bt_assert_msg(n == nw, "fmt=\"%s\" returns n=%d, want %d", fmt, n, nw); \
+ bt_assert_msg(buf[n] == 0, "fmt=\"%s\" buf[%d] should be \'\\0\', found 0x%02x", fmt, n, buf[n]); \
+ bt_assert_msg(memcmp(buf, res, nw) == 0, "fmt=\"%s\" writes \"%*s\", want \"%*s\"", fmt, (n < nw ? n : nw), buf, nw, res); \
+ } while (0)
+
+static int
+t_simple(void)
+{
+ char buf[256];
+ memset(buf, 0xa5, 256);
+
+ BSPRINTF(0, "", buf, "", NULL);
+ BSPRINTF(1, "%", buf, "%%", NULL);
+ BSPRINTF(2, "%%", buf, "%%%%", NULL);
+
+ BSPRINTF(1, "\x00", buf, "%c", 0);
+ BSPRINTF(1, "@", buf, "@", 64);
+ BSPRINTF(1, "\xff", buf, "%c", 0xff);
+
+ errno = 5;
+ BSPRINTF(18, "Input/output error", buf, "%m");
+ errno = 0;
+
+ BSPRINTF(18, "Input/output error", buf, "%M", 5);
+
+ BSPRINTF(11, "TeSt%StRiNg", buf, "%s", "TeSt%StRiNg");
+
+ if (sizeof(void *) == 4)
+ BSPRINTF(8, "1a15600d", buf, "%p", (void *) 0x1a15600d);
+ else
+ BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
+
+ long ln = 0;
+ BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
+ bt_assert_msg(ln == 5, "fmt=\"TeStS%%lntRiNg\", &ln makes ln=%ld, want 5", ln);
+
+ BSPRINTF(2, "%d", buf, "%%d", 1);
+ BSPRINTF(1, "1", buf, "%d", 1);
+ BSPRINTF(2, "+1", buf, "%+d", 1);
+ BSPRINTF(2, " 1", buf, "% d", 1);
+ BSPRINTF(2, "-1", buf, "%d", -1);
+ BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_simple, "printf without varargs");
+
+ return bt_exit_value();
+}
diff --git a/lib/slist_test.c b/lib/slist_test.c
new file mode 100644
index 00000000..fd0b1ca6
--- /dev/null
+++ b/lib/slist_test.c
@@ -0,0 +1,384 @@
+/*
+ * BIRD Library -- Safe Linked Lists Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/slists.h"
+
+#define MAX_NUM 1000
+
+static snode nodes[MAX_NUM];
+static slist lst;
+
+static void
+show_list(void)
+{
+ bt_debug("\n");
+ bt_debug("list.null is at %p and point to %p \n", &lst.null, lst.null);
+ bt_debug("list.head is at %p and point to %p \n", &lst.head, lst.head);
+ bt_debug("list.tail is at %p and point to %p \n", &lst.tail, lst.tail);
+ bt_debug("list.tail_readers is at %p and point to %p \n", &lst.tail_readers, lst.tail_readers);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_debug("n[%3i] is at %p, .prev (%p) points to %p, .next (%p) points to %p, .readers (%p) points to %p \n",
+ i, &nodes[i], &(nodes[i].prev), nodes[i].prev, &(nodes[i].next), nodes[i].next, &(nodes[i].readers), nodes[i].readers);
+}
+
+static int
+is_filled_list_well_linked(void)
+{
+ int i;
+ bt_assert(lst.head == &nodes[0]);
+ bt_assert(lst.tail == &nodes[MAX_NUM-1]);
+ bt_assert((void *) nodes[0].prev == (void *) &lst.head);
+ bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &lst.null);
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ if (i < (MAX_NUM-1))
+ bt_assert(nodes[i].next == &nodes[i+1]);
+
+ if (i > 0)
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+
+ return 1;
+}
+
+static int
+is_empty_list_well_unlinked(void)
+{
+ bt_assert(lst.head == SNODE &lst.null);
+ bt_assert(lst.tail == SNODE &lst.head);
+
+ bt_assert(EMPTY_SLIST(lst));
+
+ return 1;
+}
+
+static void
+init_list__(slist *l, struct snode nodes[])
+{
+ s_init_list(l);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].next = NULL;
+ nodes[i].prev = NULL;
+ }
+}
+
+static void
+init_list_(void)
+{
+ init_list__(&lst, nodes);
+}
+
+static int
+t_add_tail(void)
+{
+ int i;
+
+ init_list_();
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ s_add_tail(&lst, &nodes[i]);
+ bt_debug(".");
+ bt_assert(lst.tail == &nodes[i]);
+ bt_assert(lst.head == &nodes[0]);
+ bt_assert((void *) nodes[i].next == (void *) &lst.null);
+ if (i > 0)
+ {
+ bt_assert(nodes[i-1].next == &nodes[i]);
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+ }
+
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static int
+t_add_head(void)
+{
+ int i;
+
+ init_list_();
+ for (i = MAX_NUM-1; i >= 0; i--)
+ {
+ s_add_head(&lst, &nodes[i]);
+ bt_debug(".");
+ bt_assert(lst.head == &nodes[i]);
+ bt_assert(lst.tail == &nodes[MAX_NUM-1]);
+ if (i < MAX_NUM-1)
+ {
+ bt_assert(nodes[i+1].prev == &nodes[i]);
+ bt_assert(nodes[i].next == &nodes[i+1]);
+ }
+ }
+
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static void
+insert_node_(snode *n, snode *after)
+{
+ s_insert_node(n, after);
+ bt_debug(".");
+}
+
+static int
+t_insert_node(void)
+{
+ int i;
+
+ init_list_();
+
+ // add first node
+ insert_node_(&nodes[0], SNODE &lst.head);
+
+ // add odd nodes
+ for (i = 2; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-2]);
+
+ // add even nodes
+ for (i = 1; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-1]);
+
+ bt_debug("\n");
+ bt_assert(is_filled_list_well_linked());
+
+ return BT_SUCCESS;
+}
+
+static void
+fill_list2(slist *l, snode nodes[])
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ s_add_tail(l, &nodes[i]);
+}
+
+static void
+fill_list(void)
+{
+ fill_list2(&lst, SNODE nodes);
+}
+
+
+static int
+t_remove_node(void)
+{
+ int i;
+
+ init_list_();
+
+ /* Fill & Remove & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i++)
+ s_rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ /* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i+=2)
+ s_rem_node(&nodes[i]);
+
+ int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
+ bt_assert(lst.head == &nodes[1]);
+ bt_assert(lst.tail == &nodes[tail_node_index]);
+ bt_assert(nodes[tail_node_index].next == SNODE &lst.null);
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ {
+ if (i > 1)
+ bt_assert(nodes[i].prev == &nodes[i-2]);
+ if (i < tail_node_index)
+ bt_assert(nodes[i].next == &nodes[i+2]);
+ }
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ s_rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ return BT_SUCCESS;
+}
+
+static int
+t_add_tail_list(void)
+{
+ snode nodes2[MAX_NUM];
+ slist l2;
+
+ init_list__(&lst, SNODE &nodes);
+ fill_list2(&lst, SNODE &nodes);
+
+ init_list__(&l2, SNODE &nodes2);
+ fill_list2(&l2, SNODE &nodes2);
+
+ s_add_tail_list(&lst, &l2);
+
+ bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
+ bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
+ bt_assert(lst.tail == &nodes2[MAX_NUM-1]);
+
+ return BT_SUCCESS;
+}
+
+void
+dump(const char *str, slist *a)
+{
+ snode *x;
+
+ bt_debug("%s \n", str);
+ for (x = SHEAD(*a); x; x = x->next)
+ {
+ siterator *i, *j;
+ bt_debug("%p", x);
+ j = (siterator *) x;
+ for (i = x->readers; i; i = i->next)
+ {
+ if (i->prev != j)
+ bt_debug(" ???");
+ j = i;
+ bt_debug(" [%p:%p]", i, i->node);
+ }
+ bt_debug("\n");
+ }
+ bt_debug("---\n");
+}
+
+static int
+t_iterator_walk(void)
+{
+ snode *node;
+ siterator iter;
+
+ init_list_();
+ fill_list();
+
+ int k;
+ int i = 0;
+
+ show_list();
+
+ s_init(&iter, &lst);
+ WALK_SLIST(node, lst)
+ {
+ s_get(&iter);
+ s_put(&iter, node);
+ bt_debug("node->readers: %p, iter: %p, nodes[%d].readers: %p, node: %p, nodes[i]: %p, node->next: %p \n",
+ node->readers, &iter, i, nodes[i].readers, node, &(nodes[i]), node->next);
+ bt_assert(node->readers == &iter);
+ bt_assert(node->readers == nodes[i].readers);
+ bt_assert(node == &(nodes[i]));
+ for (k = 0; k < MAX_NUM; k++)
+ if (k != i)
+ bt_assert(nodes[k].readers == NULL);
+
+ dump("",&lst);
+ i++;
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_original(void)
+{
+ slist a, b;
+ snode *x, *y;
+ siterator i, j;
+
+ s_init_list(&a);
+ s_init_list(&b);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ dump("1", &a);
+
+ s_init(&i, &a);
+ s_init(&j, &a);
+ dump("2", &a);
+
+ x = s_get(&i);
+ bt_debug("Got %p\n", x);
+ dump("3", &a);
+
+ s_put(&i, x->next);
+ dump("4", &a);
+
+ y = s_get(&j);
+ while (y)
+ {
+ s_put(&j, y);
+ dump("5*", &a);
+ y = s_get(&j)->next;
+ }
+
+ dump("5 done", &a);
+
+ s_rem_node(a.head->next);
+ dump("6 (deletion)", &a);
+
+ s_put(&i, s_get(&i)->next);
+ dump("6 (relink)", &a);
+
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&b, x);
+ dump("7 (second list)", &b);
+
+ s_add_tail_list(&b, &a);
+ dump("8 (after merge)", &b);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_safe_del_walk(void)
+{
+ init_list_();
+ fill_list();
+
+ show_list();
+
+ snode *node, *node_next;
+ WALK_SLIST_DELSAFE(node,node_next, lst)
+ {
+ bt_debug("Will remove node %p \n", node);
+ s_rem_node(SNODE node);
+ }
+ bt_assert(is_empty_list_well_unlinked());
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_add_tail, "Adding nodes to tail of list");
+ bt_test_suite(t_add_head, "Adding nodes to head of list");
+ bt_test_suite(t_insert_node, "Inserting nodes to list");
+ bt_test_suite(t_remove_node, "Removing nodes from list");
+ bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
+ bt_test_suite(t_iterator_walk, "Iterator walk");
+ bt_test_suite(t_safe_del_walk, "WALK_SLIST_DELSAFE and s_rem_node all nodes");
+ bt_test_suite(t_original, "The original BIRD test suit for SLIST");
+
+ return bt_exit_value();
+}
diff --git a/lib/slists.c b/lib/slists.c
index 6e0df39e..00f3c84f 100644
--- a/lib/slists.c
+++ b/lib/slists.c
@@ -150,85 +150,3 @@ s_add_tail_list(slist *to, slist *l)
to->tail = q;
s_merge((snode *) &l->null, (snode *) &to->null);
}
-
-#ifdef TEST
-
-#include "lib/resource.h"
-#include <stdio.h>
-
-void dump(char *c, slist *a)
-{
- snode *x;
-
- puts(c);
- for(x=SHEAD(*a); x; x=x->next)
- {
- siterator *i, *j;
- printf("%p", x);
- j = (siterator *) x;
- for(i=x->readers; i; i=i->next)
- {
- if (i->prev != j)
- printf(" ???");
- j = i;
- printf(" [%p:%p]", i, i->node);
- }
- putchar('\n');
- }
- puts("---");
-}
-
-int main(void)
-{
- slist a, b;
- snode *x, *y;
- siterator i, j;
-
- s_init_list(&a);
- s_init_list(&b);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- dump("1", &a);
-
- s_init(&i, &a);
- s_init(&j, &a);
- dump("2", &a);
-
- x = s_get(&i);
- printf("Got %p\n", x);
- dump("3", &a);
-
- s_put(&i, x->next);
- dump("4", &a);
-
- y = s_get(&j);
- while (y)
- {
- s_put(&j, y);
- dump("5*", &a);
- y = s_get(&j)->next;
- }
-
- dump("5 done", &a);
-
- s_rem_node(a.head->next);
- dump("6 (deletion)", &a);
-
- s_put(&i, s_get(&i)->next);
- dump("6 (relink)", &a);
-
- x = xmalloc(sizeof(*x));
- s_add_tail(&b, x);
- dump("7 (second list)", &b);
-
- s_add_tail_list(&b, &a);
- dump("8 (after merge)", &b);
-
- return 0;
-}
-
-#endif
diff --git a/nest/Makefile b/nest/Makefile
index 6f0f9a08..d673cee5 100644
--- a/nest/Makefile
+++ b/nest/Makefile
@@ -2,3 +2,7 @@ src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_src := a-set_test.c a-path_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/nest/a-path.c b/nest/a-path.c
index b453f702..bc2216a0 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -20,7 +20,7 @@
#define put_as put_u32
#define get_as get_u32
-#define BS 4
+#define BS 4 /* Base (default) size of ASN (autonomous system number) */
struct adata *
as_path_prepend(struct linpool *pool, struct adata *olda, u32 as)
@@ -499,7 +499,6 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
* (auxiliary position after last real position in AS path)
* is marked.
*/
-
int
as_path_match(struct adata *path, struct f_path_mask *mask)
{
diff --git a/nest/a-path_test.c b/nest/a-path_test.c
new file mode 100644
index 00000000..2dc46dbe
--- /dev/null
+++ b/nest/a-path_test.c
@@ -0,0 +1,214 @@
+/*
+ * BIRD -- Path Operations Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "nest/route.h"
+#include "nest/attrs.h"
+#include "lib/resource.h"
+
+#define TESTS_NUM 30
+#define AS_PATH_LENGTH 1000
+
+#if AS_PATH_LENGTH > AS_PATH_MAXLEN
+#warning "AS_PATH_LENGTH should be <= AS_PATH_MAXLEN"
+#endif
+
+static int
+t_as_path_match(void)
+{
+ resource_init();
+
+ int round;
+ for (round = 0; round < TESTS_NUM; round++)
+ {
+ struct adata empty_as_path = {};
+ struct adata *as_path = &empty_as_path;
+ u32 first_prepended, last_prepended;
+ first_prepended = last_prepended = 0;
+ struct linpool *lp = lp_new(&root_pool, 0);
+
+ struct f_path_mask mask[AS_PATH_LENGTH] = {};
+ int i;
+ for (i = 0; i < AS_PATH_LENGTH; i++)
+ {
+ u32 val = bt_random();
+ as_path = as_path_prepend(lp, as_path, val);
+ bt_debug("Prepending ASN: %10u \n", val);
+
+ if (i == 0)
+ first_prepended = val;
+ if (i == AS_PATH_LENGTH-1)
+ last_prepended = val;
+
+ mask[i].kind = PM_ASN;
+ mask[i].val = val;
+ if (i)
+ mask[i].next = &mask[i-1];
+ }
+
+ bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path");
+
+ u32 asn;
+
+ bt_assert(as_path_get_first(as_path, &asn));
+ bt_assert_msg(asn == last_prepended, "as_path_get_first() should return the last prepended ASN");
+
+ bt_assert(as_path_get_last(as_path, &asn));
+ bt_assert_msg(asn == first_prepended, "as_path_get_last() should return the first prepended ASN");
+
+ rfree(lp);
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+t_path_format(void)
+{
+ resource_init();
+
+ struct adata empty_as_path = {};
+ struct adata *as_path = &empty_as_path;
+ struct linpool *lp = lp_new(&root_pool, 0);
+
+ uint i;
+ for (i = 4294967285; i <= 4294967294; i++)
+ {
+ as_path = as_path_prepend(lp, as_path, i);
+ bt_debug("Prepending ASN: %10u \n", i);
+ }
+
+#define BUFFER_SIZE 26
+ byte buf[BUFFER_SIZE] = {};
+ as_path_format(as_path, buf, BUFFER_SIZE);
+ bt_assert_msg(strcmp(buf, "4294967294 4294967293 ...") == 0, "Buffer(%zu): '%s'", strlen(buf), buf);
+
+#define SMALL_BUFFER_SIZE 25
+ byte buf2[SMALL_BUFFER_SIZE] = {};
+ as_path_format(as_path, buf2, SMALL_BUFFER_SIZE);
+ bt_assert_msg(strcmp(buf2, "4294967294 ...") == 0, "Small Buffer(%zu): '%s'", strlen(buf2), buf2);
+
+ rfree(lp);
+
+ return BT_SUCCESS;
+}
+
+static int
+count_asn_in_array(const u32 *array, u32 asn)
+{
+ int counts_of_contains = 0;
+ int u;
+ for (u = 0; u < AS_PATH_LENGTH; u++)
+ if (array[u] == asn)
+ counts_of_contains++;
+ return counts_of_contains;
+}
+
+static int
+t_path_include(void)
+{
+ resource_init();
+
+ struct adata empty_as_path = {};
+ struct adata *as_path = &empty_as_path;
+ struct linpool *lp = lp_new(&root_pool, 0);
+
+ u32 as_nums[AS_PATH_LENGTH] = {};
+ int i;
+ for (i = 0; i < AS_PATH_LENGTH; i++)
+ {
+ u32 val = bt_random();
+ as_nums[i] = val;
+ as_path = as_path_prepend(lp, as_path, val);
+ }
+
+ for (i = 0; i < AS_PATH_LENGTH; i++)
+ {
+ int counts_of_contains = count_asn_in_array(as_nums, as_nums[i]);
+ bt_assert_msg(as_path_contains(as_path, as_nums[i], counts_of_contains), "AS Path should contains %d-times number %d", counts_of_contains, as_nums[i]);
+
+ bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 0) != NULL);
+ bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 1) != NULL);
+ }
+
+ for (i = 0; i < 10000; i++)
+ {
+ u32 test_val = bt_random();
+ int counts_of_contains = count_asn_in_array(as_nums, test_val);
+ int result = as_path_contains(as_path, test_val, (counts_of_contains == 0 ? 1 : counts_of_contains));
+
+ if (counts_of_contains)
+ bt_assert_msg(result, "As path should contain %d-times the number %u", counts_of_contains, test_val);
+ else
+ bt_assert_msg(result == 0, "As path should not contain the number %u", test_val);
+ }
+
+ rfree(lp);
+
+ return BT_SUCCESS;
+}
+
+static int
+t_as_path_converting(void)
+{
+ resource_init();
+
+ struct adata empty_as_path = {};
+ struct adata *as_path = &empty_as_path;
+ struct linpool *lp = lp_new(&root_pool, 0);
+#define AS_PATH_LENGTH_FOR_CONVERTING_TEST 10
+
+ int i;
+ for (i = 0; i < AS_PATH_LENGTH_FOR_CONVERTING_TEST; i++)
+ as_path = as_path_prepend(lp, as_path, i);
+
+ bt_debug("data length: %u \n", as_path->length);
+
+ byte buffer[100] = {};
+ int used_size = as_path_convert_to_new(as_path, buffer, AS_PATH_LENGTH_FOR_CONVERTING_TEST-1);
+ bt_debug("as_path_convert_to_new: len %d \n%s\n", used_size, buffer);
+ for (i = 0; i < used_size; i++)
+ {
+ bt_debug("\\03%d", buffer[i]);
+ }
+ bt_debug("\n");
+ bt_assert(memcmp(buffer,
+ "\032\039\030\030\030\030\030\030\030\039\030\030\030\030\030\030\030\038\030\030\030\030\030\030"
+ "\030\037\030\030\030\030\030\030\030\036\030\030\030\030",
+ 38));
+
+ bzero(buffer, sizeof(buffer));
+ int new_used;
+ used_size = as_path_convert_to_old(as_path, buffer, &new_used);
+ bt_debug("as_path_convert_to_old: len %d, new_used: %d \n", used_size, new_used);
+ for (i = 0; i < used_size; i++)
+ {
+ bt_debug("\\03%d", buffer[i]);
+ }
+ bt_debug("\n");
+ bt_assert(memcmp(buffer,
+ "\032\0310\030\039\030\038\030\037\030\036\030\035\030\034\030\033\030\032\030\031\030\030",
+ 22));
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_as_path_match, "Testing AS path matching and some a-path utilities.");
+ bt_test_suite(t_path_format, "Testing formating as path into byte buffer");
+ bt_test_suite(t_path_include, "Testing including a AS number in AS path");
+ bt_test_suite(t_as_path_converting, "Testing as_path_convert_to_*() output constancy");
+
+ return bt_exit_value();
+}
diff --git a/nest/a-set_test.c b/nest/a-set_test.c
new file mode 100644
index 00000000..763b6b9f
--- /dev/null
+++ b/nest/a-set_test.c
@@ -0,0 +1,260 @@
+/*
+ * BIRD -- Set/Community-list Operations Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "lib/net.h"
+#include "nest/route.h"
+#include "nest/attrs.h"
+#include "lib/resource.h"
+
+#define SET_SIZE 10
+static struct adata *set_sequence; /* <0; SET_SIZE) */
+static struct adata *set_sequence_same; /* <0; SET_SIZE) */
+static struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
+static struct adata *set_random;
+
+#define BUFFER_SIZE 1000
+static byte buf[BUFFER_SIZE] = {};
+
+#define SET_SIZE_FOR_FORMAT_OUTPUT 10
+
+struct linpool *lp;
+
+enum set_type
+{
+ SET_TYPE_INT,
+ SET_TYPE_EC
+};
+
+static void
+generate_set_sequence(enum set_type type)
+{
+ struct adata empty_as_path = {};
+ set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
+ lp = lp_new(&root_pool, 0);
+
+ int i;
+ for (i = 0; i < SET_SIZE; i++)
+ {
+ if (type == SET_TYPE_INT)
+ {
+ set_sequence = int_set_add(lp, set_sequence, i);
+ set_sequence_same = int_set_add(lp, set_sequence_same, i);
+ set_sequence_higher = int_set_add(lp, set_sequence_higher, i + SET_SIZE);
+ set_random = int_set_add(lp, set_random, bt_random());
+ }
+ else if (type == SET_TYPE_EC)
+ {
+ set_sequence = ec_set_add(lp, set_sequence, i);
+ set_sequence_same = ec_set_add(lp, set_sequence_same, i);
+ set_sequence_higher = ec_set_add(lp, set_sequence_higher, i + SET_SIZE);
+ set_random = ec_set_add(lp, set_random, (bt_random() << 32 | bt_random()));
+ }
+ else
+ bt_abort_msg("This should be unreachable");
+ }
+}
+
+/*
+ * SET INT TESTS
+ */
+
+static int
+t_set_int_contains(void)
+{
+ int i;
+
+ resource_init();
+ generate_set_sequence(SET_TYPE_INT);
+
+ bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
+
+ for (i = 0; i < SET_SIZE; i++)
+ bt_assert(int_set_contains(set_sequence, i));
+ bt_assert(int_set_contains(set_sequence, -1) == 0);
+ bt_assert(int_set_contains(set_sequence, SET_SIZE) == 0);
+
+ int *data = int_set_get_data(set_sequence);
+ for (i = 0; i < SET_SIZE; i++)
+ bt_assert_msg(data[i] == i, "(data[i] = %d) == i = %d)", data[i], i);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_int_union(void)
+{
+ resource_init();
+ generate_set_sequence(SET_TYPE_INT);
+
+ struct adata *set_union;
+ set_union = int_set_union(lp, set_sequence, set_sequence_same);
+ bt_assert(int_set_get_size(set_union) == SET_SIZE);
+ bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
+
+ set_union = int_set_union(lp, set_sequence, set_sequence_higher);
+ bt_assert_msg(int_set_get_size(set_union) == SET_SIZE*2, "int_set_get_size(set_union) %d, SET_SIZE*2 %d", int_set_get_size(set_union), SET_SIZE*2);
+ bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_int_format(void)
+{
+ resource_init();
+ generate_set_sequence(SET_TYPE_INT);
+
+ set_sequence->length = 4 * SET_SIZE_FOR_FORMAT_OUTPUT; /* dirty */
+ bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0);
+ bt_assert(strcmp(buf, "0.0.0.0 0.0.0.1 0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
+
+ bzero(buf, BUFFER_SIZE);
+ bt_assert(int_set_format(set_sequence, 0, 2, buf, BUFFER_SIZE) == 0);
+ bt_assert(strcmp(buf, "0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
+
+ bzero(buf, BUFFER_SIZE);
+ bt_assert(int_set_format(set_sequence, 1, 0, buf, BUFFER_SIZE) == 0);
+ bt_assert(strcmp(buf, "(0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9)") == 0);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_int_delete(void)
+{
+ resource_init();
+ generate_set_sequence(SET_TYPE_INT);
+
+ struct adata *deleting_sequence = set_sequence;
+ u32 i;
+ for (i = 0; i < SET_SIZE; i++)
+ {
+ deleting_sequence = int_set_del(lp, deleting_sequence, i);
+ bt_assert_msg(int_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
+ "int_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
+ int_set_get_size(deleting_sequence),
+ SET_SIZE-1-i);
+ }
+
+ bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
+
+ return BT_SUCCESS;
+}
+
+/*
+ * SET EC TESTS
+ */
+
+static int
+t_set_ec_contains(void)
+{
+ u32 i;
+
+ resource_init();
+ generate_set_sequence(SET_TYPE_EC);
+
+ bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
+
+ for (i = 0; i < SET_SIZE; i++)
+ bt_assert(ec_set_contains(set_sequence, i));
+ bt_assert(ec_set_contains(set_sequence, -1) == 0);
+ bt_assert(ec_set_contains(set_sequence, SET_SIZE) == 0);
+
+// int *data = ec_set_get_data(set_sequence);
+// for (i = 0; i < SET_SIZE; i++)
+// bt_assert_msg(data[i] == (SET_SIZE-1-i), "(data[i] = %d) == ((SET_SIZE-1-i) = %d)", data[i], SET_SIZE-1-i);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_ec_union(void)
+{
+ resource_init();
+ generate_set_sequence(SET_TYPE_EC);
+
+ struct adata *set_union;
+ set_union = ec_set_union(lp, set_sequence, set_sequence_same);
+ bt_assert(ec_set_get_size(set_union) == SET_SIZE);
+ bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
+
+ set_union = ec_set_union(lp, set_sequence, set_sequence_higher);
+ bt_assert_msg(ec_set_get_size(set_union) == SET_SIZE*2, "ec_set_get_size(set_union) %d, SET_SIZE*2 %d", ec_set_get_size(set_union), SET_SIZE*2);
+ bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_ec_format(void)
+{
+ resource_init();
+
+ struct adata empty_as_path = {};
+ set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
+ lp = lp_new(&root_pool, 0);
+
+ u64 i = 0;
+ set_sequence = ec_set_add(lp, set_sequence, i);
+ for (i = 1; i < SET_SIZE_FOR_FORMAT_OUTPUT; i++)
+ set_sequence = ec_set_add(lp, set_sequence, i + ((i%2) ? ((u64)EC_RO << 48) : ((u64)EC_RT << 48)));
+
+ bt_assert(ec_set_format(set_sequence, 0, buf, BUFFER_SIZE) == 0);
+ bt_assert_msg(strcmp(buf, "(unknown 0x0, 0, 0) (ro, 0, 1) (rt, 0, 2) (ro, 0, 3) (rt, 0, 4) (ro, 0, 5) (rt, 0, 6) (ro, 0, 7) (rt, 0, 8) (ro, 0, 9)") == 0,
+ "ec_set_format() returns '%s'", buf);
+
+ rfree(lp);
+ return BT_SUCCESS;
+}
+
+static int
+t_set_ec_delete(void)
+{
+ resource_init();
+ generate_set_sequence(SET_TYPE_EC);
+
+ struct adata *deleting_sequence = set_sequence;
+ u32 i;
+ for (i = 0; i < SET_SIZE; i++)
+ {
+ deleting_sequence = ec_set_del(lp, deleting_sequence, i);
+ bt_assert_msg(ec_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
+ "ec_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
+ ec_set_get_size(deleting_sequence), SET_SIZE-1-i);
+ }
+
+ bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
+
+ return BT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_set_int_contains, "Testing sets of integers: contains, get_data");
+ bt_test_suite(t_set_int_format, "Testing sets of integers: format");
+ bt_test_suite(t_set_int_union, "Testing sets of integers: union");
+ bt_test_suite(t_set_int_delete, "Testing sets of integers: delete");
+
+ bt_test_suite(t_set_ec_contains, "Testing sets of Extended Community values: contains, get_data");
+ bt_test_suite(t_set_ec_format, "Testing sets of Extended Community values: format");
+ bt_test_suite(t_set_ec_union, "Testing sets of Extended Community values: union");
+ bt_test_suite(t_set_ec_delete, "Testing sets of Extended Community values: delete");
+
+ return bt_exit_value();
+}
diff --git a/nest/iface.h b/nest/iface.h
index c4f414ec..d960b859 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -10,6 +10,7 @@
#define _BIRD_IFACE_H_
#include "lib/lists.h"
+#include "lib/ip.h"
extern list iface_list;
diff --git a/nest/route.h b/nest/route.h
index f2e883b6..5104d8f1 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -12,7 +12,7 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "sysdep/unix/timer.h"
-//#include "nest/protocol.h"
+#include "lib/net.h"
struct ea_list;
struct protocol;
diff --git a/proto/bfd/Makefile b/proto/bfd/Makefile
index 489216d8..402122fc 100644
--- a/proto/bfd/Makefile
+++ b/proto/bfd/Makefile
@@ -2,3 +2,5 @@ src := bfd.c io.c packets.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/bgp/Makefile b/proto/bgp/Makefile
index f4958867..00aaef5e 100644
--- a/proto/bgp/Makefile
+++ b/proto/bgp/Makefile
@@ -2,3 +2,5 @@ src := attrs.c bgp.c packets.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/ospf/Makefile b/proto/ospf/Makefile
index fe52ed30..39e74f71 100644
--- a/proto/ospf/Makefile
+++ b/proto/ospf/Makefile
@@ -2,3 +2,5 @@ src := dbdes.c hello.c iface.c lsack.c lsalib.c lsreq.c lsupd.c neighbor.c ospf.
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index c5c54783..054841ca 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1921,7 +1921,7 @@ rt_sync(struct ospf_proto *p)
/* This is used for forced reload of routes */
int reload = (p->calcrt == 2);
- OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
+ OSPF_TRACE(D_EVENTS, "Starting routing table synchronization");
DBG("Now syncing my rt table with nest's\n");
FIB_ITERATE_INIT(&fit, fib);
diff --git a/proto/pipe/Makefile b/proto/pipe/Makefile
index c258a3e5..5093da98 100644
--- a/proto/pipe/Makefile
+++ b/proto/pipe/Makefile
@@ -2,3 +2,5 @@ src := pipe.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/radv/Makefile b/proto/radv/Makefile
index 3584a5f3..05317eff 100644
--- a/proto/radv/Makefile
+++ b/proto/radv/Makefile
@@ -2,3 +2,5 @@ src := packets.c radv.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 44b44879..d7d975ab 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -311,7 +311,7 @@ radv_check_active(struct proto_radv *ra)
if (!radv_trigger_valid(cf))
return 1;
- struct channel *c =ra->p.main_channel;
+ struct channel *c = ra->p.main_channel;
return rt_examine(c->table, &cf->trigger, &ra->p, c->out_filter);
}
diff --git a/proto/rip/Makefile b/proto/rip/Makefile
index 6e645cc2..7feabcd8 100644
--- a/proto/rip/Makefile
+++ b/proto/rip/Makefile
@@ -2,3 +2,5 @@ src := packets.c rip.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/static/Makefile b/proto/static/Makefile
index 3ace39cf..e38f9b74 100644
--- a/proto/static/Makefile
+++ b/proto/static/Makefile
@@ -2,3 +2,5 @@ src := static.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in
index c73270c3..0d0627f3 100644
--- a/sysdep/autoconf.h.in
+++ b/sysdep/autoconf.h.in
@@ -67,4 +67,7 @@
/* We have stdint.h */
#undef HAVE_STDINT_H
+/* We have execinfo.h */
+#undef HAVE_EXECINFO_H
+
#define CONFIG_PATH ?
diff --git a/sysdep/bsd/Makefile b/sysdep/bsd/Makefile
index ddc87239..dfa32747 100644
--- a/sysdep/bsd/Makefile
+++ b/sysdep/bsd/Makefile
@@ -3,3 +3,4 @@ obj := $(src-o-files)
$(all-daemon)
$(conf-y-targets): $(s)krt-sock.Y
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/sysdep/linux/Makefile b/sysdep/linux/Makefile
index 23cf1d9d..188ac8de 100644
--- a/sysdep/linux/Makefile
+++ b/sysdep/linux/Makefile
@@ -2,3 +2,5 @@ src := netlink.c
obj := $(src-o-files)
$(all-daemon)
$(conf-y-targets): $(s)netlink.Y
+
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile
index c5d55431..f592399c 100644
--- a/sysdep/unix/Makefile
+++ b/sysdep/unix/Makefile
@@ -3,3 +3,6 @@ obj := $(src-o-files)
$(all-daemon)
$(cf-local)
$(conf-y-targets): $(s)krt.Y
+
+src := $(filter-out main.c, $(src))
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 00000000..2cee9234
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,3 @@
+src := birdtest.c bt-utils.c
+obj := $(src-o-files)
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/test/birdtest.c b/test/birdtest.c
new file mode 100644
index 00000000..4e8645a4
--- /dev/null
+++ b/test/birdtest.c
@@ -0,0 +1,488 @@
+/*
+ * BIRD -- Unit Test Framework (BIRD Test)
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "test/birdtest.h"
+#include "lib/string.h"
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#define BACKTRACE_MAX_LINES 100
+
+#define sprintf_concat(s, format, ...) \
+ snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
+
+static const char *request;
+static int list_tests;
+static int do_core;
+static int no_fork;
+static int no_timeout;
+static int is_terminal; /* Whether stdout is a live terminal or pipe redirect */
+
+uint bt_verbose;
+const char *bt_filename;
+const char *bt_test_id;
+
+int bt_result; /* Overall program run result */
+int bt_suite_result; /* One suit result */
+char bt_out_fmt_buf[1024]; /* Temporary memory buffer for output of testing function */
+
+long int
+bt_random(void)
+{
+ /* Seeded in bt_init() */
+ long int rand_low, rand_high;
+
+ rand_low = random();
+ rand_high = random();
+ return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
+}
+
+void
+bt_init(int argc, char *argv[])
+{
+ int c;
+
+ srandom(BT_RANDOM_SEED);
+
+ bt_verbose = 0;
+ bt_filename = argv[0];
+ bt_result = BT_SUCCESS;
+ bt_test_id = NULL;
+ is_terminal = isatty(fileno(stdout));
+
+ while ((c = getopt(argc, argv, "lcftv")) >= 0)
+ switch (c)
+ {
+ case 'l':
+ list_tests = 1;
+ break;
+
+ case 'c':
+ do_core = 1;
+ break;
+
+ case 'f':
+ no_fork = 1;
+ break;
+
+ case 't':
+ no_timeout = 1;
+ break;
+
+ case 'v':
+ bt_verbose++;
+ break;
+
+ default:
+ goto usage;
+ }
+
+ /* Optional requested test_id */
+ if ((optind + 1) == argc)
+ request = argv[optind++];
+
+ if (optind != argc)
+ goto usage;
+
+ if (do_core)
+ {
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ int rv = setrlimit(RLIMIT_CORE, &rl);
+ bt_syscall(rv < 0, "setrlimit RLIMIT_CORE");
+ }
+
+ return;
+
+ usage:
+ printf("Usage: %s [-l] [-c] [-f] [-t] [-vvv] [<test_suit_name>]\n", argv[0]);
+ printf("Options: \n");
+ printf(" -l List all test suite names and descriptions \n");
+ printf(" -c Force unlimit core dumps (needs root privileges) \n");
+ printf(" -f No forking \n");
+ printf(" -t No timeout limit \n");
+ printf(" -v More verbosity, maximum is 3 -vvv \n");
+ exit(3);
+}
+
+static void
+bt_dump_backtrace(void)
+{
+#ifdef HAVE_EXECINFO_H
+ void *buf[BACKTRACE_MAX_LINES];
+ char **pp_backtrace;
+ int lines, j;
+
+ if (!bt_verbose)
+ return;
+
+ lines = backtrace(buf, BACKTRACE_MAX_LINES);
+ bt_log("backtrace() returned %d addresses", lines);
+
+ pp_backtrace = backtrace_symbols(buf, lines);
+ if (pp_backtrace == NULL)
+ {
+ perror("backtrace_symbols");
+ exit(EXIT_FAILURE);
+ }
+
+ for (j = 0; j < lines; j++)
+ bt_log("%s", pp_backtrace[j]);
+
+ free(pp_backtrace);
+#endif /* HAVE_EXECINFO_H */
+}
+
+static
+int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout)
+{
+ int result;
+ alarm(timeout);
+
+ if (fn_arg)
+ result = fn(fn_arg);
+ else
+ result = ((int (*)(void))fn)();
+
+ if (bt_suite_result != BT_SUCCESS)
+ result = BT_FAILURE;
+
+ return result;
+}
+
+static uint
+get_num_terminal_cols(void)
+{
+ struct winsize w = {};
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
+ uint cols = w.ws_col;
+ return (cols > 0 ? cols : 80);
+}
+
+/**
+ * bt_log_result - pretty print of test result
+ * @result: BT_SUCCESS or BT_FAILURE
+ * @fmt: a description message (could be long, over more lines)
+ * @argptr: variable argument list
+ *
+ * This function is used for pretty printing of test results on all verbose
+ * levels.
+ */
+static void
+bt_log_result(int result, const char *fmt, va_list argptr)
+{
+ char fmt_buf[BT_BUFFER_SIZE];
+ char msg_buf[BT_BUFFER_SIZE];
+ char *pos;
+
+ snprintf(msg_buf, sizeof(msg_buf), "%s%s%s%s",
+ bt_filename,
+ bt_test_id ? ": " : "",
+ bt_test_id ? bt_test_id : "",
+ (fmt && strlen(fmt) > 0) ? ": " : "");
+ pos = msg_buf + strlen(msg_buf);
+
+ vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
+
+ /* 'll' means here Last Line */
+ uint cols = get_num_terminal_cols();
+ uint ll_len = (strlen(msg_buf) % cols) + BT_PROMPT_OK_FAIL_STRLEN;
+ uint ll_offset = (ll_len / get_num_terminal_cols() + 1) * cols - BT_PROMPT_OK_FAIL_STRLEN;
+ uint offset = ll_offset + (strlen(msg_buf) / cols) * cols;
+ snprintf(fmt_buf, sizeof(fmt_buf), "%%-%us%%s\n", offset);
+
+ const char *result_str = is_terminal ? BT_PROMPT_OK : BT_PROMPT_OK_NO_COLOR;
+ if (result != BT_SUCCESS)
+ result_str = is_terminal ? BT_PROMPT_FAIL : BT_PROMPT_FAIL_NO_COLOR;
+
+ printf(fmt_buf, msg_buf, result_str);
+}
+
+/**
+ * bt_log_overall_result - pretty print of suite case result
+ * @result: BT_SUCCESS or BT_FAILURE
+ * @fmt: a description message (could be long, over more lines)
+ * ...: variable argument list
+ *
+ * This function is used for pretty printing of test suite case result.
+ */
+static void
+bt_log_overall_result(int result, const char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+ bt_log_result(result, fmt, argptr);
+ va_end(argptr);
+}
+
+/**
+ * bt_log_suite_result - pretty print of suite case result
+ * @result: BT_SUCCESS or BT_FAILURE
+ * @fmt: a description message (could be long, over more lines)
+ * ...: variable argument list
+ *
+ * This function is used for pretty printing of test suite case result.
+ */
+void
+bt_log_suite_result(int result, const char *fmt, ...)
+{
+ if(bt_verbose >= BT_VERBOSE_SUITE || result == BT_FAILURE)
+ {
+ va_list argptr;
+ va_start(argptr, fmt);
+ bt_log_result(result, fmt, argptr);
+ va_end(argptr);
+ }
+}
+
+/**
+ * bt_log_suite_case_result - pretty print of suite result
+ * @result: BT_SUCCESS or BT_FAILURE
+ * @fmt: a description message (could be long, over more lines)
+ * ...: variable argument list
+ *
+ * This function is used for pretty printing of test suite result.
+ */
+void
+bt_log_suite_case_result(int result, const char *fmt, ...)
+{
+ if(bt_verbose >= BT_VERBOSE_SUITE_CASE)
+ {
+ va_list argptr;
+ va_start(argptr, fmt);
+ bt_log_result(result, fmt, argptr);
+ va_end(argptr);
+ }
+}
+
+int
+bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg, int forked, int timeout, const char *dsc, ...)
+{
+ if (list_tests)
+ {
+ printf("%28s - ", id);
+ va_list args;
+ va_start(args, dsc);
+ vprintf(dsc, args);
+ va_end(args);
+ printf("\n");
+ return BT_SUCCESS;
+ }
+
+ if (no_fork)
+ forked = 0;
+
+ if (no_timeout)
+ timeout = 0;
+
+ if (request && strcmp(id, request))
+ return BT_SUCCESS;
+
+ bt_suite_result = BT_SUCCESS;
+ bt_test_id = id;
+
+ if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
+ bt_log("Starting");
+
+ if (!forked)
+ {
+ bt_suite_result = bt_run_test_fn(fn, fn_arg, timeout);
+ }
+ else
+ {
+ pid_t pid = fork();
+ bt_syscall(pid < 0, "fork");
+
+ if (pid == 0)
+ {
+ /* child of fork */
+ _exit(bt_run_test_fn(fn, fn_arg, timeout));
+ }
+
+ int s;
+ int rv = waitpid(pid, &s, 0);
+ bt_syscall(rv < 0, "waitpid");
+
+ if (WIFEXITED(s))
+ {
+ /* Normal exit */
+ bt_suite_result = WEXITSTATUS(s);
+ }
+ else if (WIFSIGNALED(s))
+ {
+ /* Stopped by signal */
+ bt_suite_result = BT_FAILURE;
+
+ int sn = WTERMSIG(s);
+ if (sn == SIGALRM)
+ {
+ bt_log("Timeout expired");
+ }
+ else if (sn == SIGSEGV)
+ {
+ bt_log("Segmentation fault");
+ bt_dump_backtrace();
+ }
+ else if (sn != SIGABRT)
+ bt_log("Signal %d received", sn);
+ }
+
+ if (WCOREDUMP(s) && bt_verbose)
+ bt_log("Core dumped");
+ }
+
+ if (bt_suite_result == BT_FAILURE)
+ bt_result = BT_FAILURE;
+
+ bt_log_suite_result(bt_suite_result, NULL);
+ bt_test_id = NULL;
+
+ return bt_suite_result;
+}
+
+int
+bt_exit_value(void)
+{
+ if (!list_tests || (list_tests && bt_result != BT_SUCCESS))
+ bt_log_overall_result(bt_result, "");
+ return bt_result == BT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+/**
+ * bt_assert_batch__ - test a batch of inputs/outputs tests
+ * @opts: includes all necessary data
+ *
+ * Should be called using macro bt_assert_batch().
+ * Returns BT_SUCCESS or BT_FAILURE.
+ */
+int
+bt_assert_batch__(struct bt_batch *opts)
+{
+ int i;
+ for (i = 0; i < opts->ndata; i++)
+ {
+ int bt_suit_case_result = opts->test_fn(opts->out_buf, opts->data[i].in, opts->data[i].out);
+
+ if (bt_suit_case_result == BT_FAILURE)
+ bt_suite_result = BT_FAILURE;
+
+ char b[BT_BUFFER_SIZE];
+ snprintf(b, sizeof(b), "%s(", opts->test_fn_name);
+
+ opts->in_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].in);
+ sprintf_concat(b, ") gives ");
+ opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->out_buf);
+
+ if (bt_suit_case_result == BT_FAILURE)
+ {
+ sprintf_concat(b, ", but expecting is ");
+ opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].out);
+ }
+
+ bt_log_suite_case_result(bt_suit_case_result, "%s", b);
+ }
+
+ return bt_suite_result;
+}
+
+/**
+ * bt_fmt_str - formating string into output buffer
+ * @buf: buffer for write
+ * @size: empty size in @buf
+ * @data: null-byte terminated string
+ *
+ * This function can be used with bt_assert_batch() function.
+ * Input @data should be const char * string.
+ */
+void
+bt_fmt_str(char *buf, size_t size, const void *data)
+{
+ const byte *s = data;
+
+ snprintf(buf, size, "\"");
+ while (*s)
+ {
+ snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(*s) ? "%c" : "\\%03u", *s);
+ s++;
+ }
+ snprintf(buf+strlen(buf), size-strlen(buf), "\"");
+}
+
+/**
+ * bt_fmt_unsigned - formating unsigned int into output buffer
+ * @buf: buffer for write
+ * @size: empty size in @buf
+ * @data: unsigned number
+ *
+ * This function can be used with bt_assert_batch() function.
+ */
+void
+bt_fmt_unsigned(char *buf, size_t size, const void *data)
+{
+ const uint *n = data;
+ snprintf(buf, size, "0x%x (%u)", *n, *n);
+}
+
+/**
+ * bt_fmt_ipa - formating ip_addr into output buffer
+ * @buf: buffer for write
+ * @size: empty size in @buf
+ * @data: should be struct ip_addr *
+ *
+ * This function can be used with bt_assert_batch() function.
+ */
+void
+bt_fmt_ipa(char *buf, size_t size, const void *data)
+{
+ const ip_addr *ip = data;
+ bsnprintf(buf, size, "%I", *ip);
+}
+
+int
+bt_is_char(byte c)
+{
+ return (c >= (byte) 32 && c <= (byte) 126);
+}
+
+/*
+ * Mock-ups of all necessary public functions in main.c
+ */
+
+char *bird_name;
+void async_config(void) {}
+void async_dump(void) {}
+void async_shutdown(void) {}
+void cmd_check_config(char *name UNUSED) {}
+void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
+void cmd_reconfig_confirm(void) {}
+void cmd_reconfig_undo(void) {}
+void cmd_shutdown(void) {}
+void cmd_reconfig_undo_notify(void) {}
+
+#include "nest/bird.h"
+#include "lib/net.h"
+#include "conf/conf.h"
+void sysdep_preconfig(struct config *c UNUSED) {}
+int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return 0; }
+void sysdep_shutdown_done(void) {}
+
+#include "nest/cli.h"
+int cli_get_command(cli *c UNUSED) { return 0; }
+void cli_write_trigger(cli *c UNUSED) {}
+cli *cmd_reconfig_stored_cli;
diff --git a/test/birdtest.h b/test/birdtest.h
new file mode 100644
index 00000000..0090712d
--- /dev/null
+++ b/test/birdtest.h
@@ -0,0 +1,183 @@
+/*
+ * BIRD -- Unit Test Framework (BIRD Test)
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRDTEST_H_
+#define _BIRDTEST_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "nest/bird.h"
+
+
+extern int bt_result;
+extern int bt_suite_result;
+extern char bt_out_fmt_buf[1024];
+
+extern uint bt_verbose;
+#define BT_VERBOSE_NO 0
+#define BT_VERBOSE_SUITE 1
+#define BT_VERBOSE_SUITE_CASE 2
+#define BT_VERBOSE_ABSOLUTELY_ALL 3
+
+extern const char *bt_filename;
+extern const char *bt_test_id;
+
+void bt_init(int argc, char *argv[]);
+int bt_exit_value(void);
+int bt_test_suite_base(int (*test_fn)(const void *), const char *test_id, const void *test_fn_argument, int forked, int timeout, const char *dsc, ...);
+long int bt_random(void);
+
+void bt_log_suite_result(int result, const char *fmt, ...);
+void bt_log_suite_case_result(int result, const char *fmt, ...);
+
+#define BT_SUCCESS 42 /* 1 is too usual, filter quitbird returns 1 too */
+#define BT_FAILURE 0
+
+#define BT_TIMEOUT 5 /* Default timeout in seconds */
+#define BT_FORKING 1 /* Forking is enabled in default */
+
+#define BT_RANDOM_SEED 982451653
+
+#define BT_BUFFER_SIZE 10000
+
+#define BT_PROMPT_GREEN "\e[1;32m"
+#define BT_PROMPT_RED "\e[1;31m"
+#define BT_PROMPT_NORMAL "\e[0m"
+#define BT_PROMPT_OK " [" BT_PROMPT_GREEN " OK " BT_PROMPT_NORMAL "] "
+#define BT_PROMPT_OK_NO_COLOR " [" " OK " "] "
+#define BT_PROMPT_FAIL " [" BT_PROMPT_RED "FAIL" BT_PROMPT_NORMAL "] "
+#define BT_PROMPT_FAIL_NO_COLOR " [" "FAIL" "] "
+#define BT_PROMPT_OK_FAIL_STRLEN 8 /* strlen ' [FAIL] ' */
+
+#define bt_test_suite(fn, dsc, ...) \
+ bt_test_suite_extra(fn, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__)
+
+#define bt_test_suite_extra(fn, f, t, dsc, ...) \
+ bt_test_suite_base((int (*)(const void *))fn, #fn, NULL, f, t, dsc, ##__VA_ARGS__)
+
+#define bt_test_suite_arg(fn, arg, dsc, ...) \
+ bt_test_suite_arg_extra(fn, arg, BT_FORKING, BT_TIMEOUT, dsc, ##__VA_ARGS__)
+
+#define bt_test_suite_arg_extra(fn, arg, f, t, dsc, ...) \
+ bt_test_suite_base(fn, #fn, arg, f, t, dsc, ##__VA_ARGS__)
+
+#define bt_abort() \
+ bt_abort_msg("Aborted at %s:%d", __FILE__, __LINE__)
+
+#define bt_abort_msg(format, ...) \
+ do \
+ { \
+ bt_log(format, ##__VA_ARGS__); \
+ abort(); \
+ } while (0)
+
+#define bt_log(format, ...) \
+ do \
+ { \
+ if (bt_test_id) \
+ printf("%s: %s: " format "\n", bt_filename, bt_test_id, ##__VA_ARGS__); \
+ else \
+ printf("%s: " format "\n", bt_filename, ##__VA_ARGS__); \
+ } while(0)
+
+#define bt_debug(format, ...) \
+ do \
+ { \
+ if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL) \
+ printf(format, ##__VA_ARGS__); \
+ } while (0)
+
+#define bt_assert(test) \
+ bt_assert_msg(test, "Assertion (%s) at %s:%d", #test, __FILE__, __LINE__)
+
+#define bt_assert_msg(test, format, ...) \
+ do \
+ { \
+ int bt_suit_case_result = BT_SUCCESS; \
+ if ((test) == 0) \
+ { \
+ bt_result = BT_FAILURE; \
+ bt_suite_result = BT_FAILURE; \
+ bt_suit_case_result = BT_FAILURE; \
+ } \
+ bt_log_suite_case_result(bt_suit_case_result, format, ##__VA_ARGS__); \
+ } while (0)
+
+#define bt_syscall(test, format, ...) \
+ do \
+ { \
+ if (test) \
+ { \
+ bt_log(format ": %s", ##__VA_ARGS__, strerror(errno)); \
+ exit(3); \
+ } \
+ } while (0)
+
+#define bt_sprintf_concat(s, format, ...) \
+ snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
+
+struct bt_pair {
+ const void *in;
+ const void *out;
+};
+
+/* Data structure used by bt_assert_batch() function */
+struct bt_batch {
+ /* in_fmt / out_fmt - formating data
+ * @buf: buffer for write stringified @data
+ * @size: empty size in @buf
+ * @data: data for stringify
+ *
+ * There are some build-in functions, see bt_fmt_* functions */
+ void (*in_fmt)(char *buf, size_t size, const void *data);
+ void (*out_fmt)(char *buf, size_t size, const void *data);
+
+ /* Temporary output buffer */
+ void *out_buf;
+
+ /* test_fn - testing function
+ * @out: output data from tested function
+ * @in: data for input
+ * @expected_out: expected data from tested function
+ *
+ * Input arguments should not be stringified using in_fmt() or out_fmt()
+ * function already. This function should return only BT_SUCCESS or
+ * BT_FAILURE */
+ int (*test_fn)(void *out, const void *in, const void *expected_out);
+
+ /* Name of testing function @test_fn */
+ const char *test_fn_name;
+
+ /* Number of items in data*/
+ int ndata;
+
+ /* Array of input and expected output pairs */
+ struct bt_pair *data;
+};
+
+void bt_fmt_str(char *buf, size_t size, const void *data);
+void bt_fmt_unsigned(char *buf, size_t size, const void *data);
+void bt_fmt_ipa(char *buf, size_t size, const void *data);
+int bt_assert_batch__(struct bt_batch *opts);
+int bt_is_char(byte c);
+
+#define bt_assert_batch(data__, fn__, in_fmt__, out_fmt__) \
+ bt_assert_batch__(& (struct bt_batch) { \
+ .data = data__, \
+ .ndata = ARRAY_SIZE(data__), \
+ .test_fn = fn__, \
+ .test_fn_name = #fn__, \
+ .in_fmt = in_fmt__, \
+ .out_fmt = out_fmt__, \
+ .out_buf = bt_out_fmt_buf, /* Global memory for this usage */ \
+ })
+
+#endif /* _BIRDTEST_H_ */
diff --git a/test/bt-utils.c b/test/bt-utils.c
new file mode 100644
index 00000000..aaeb77b8
--- /dev/null
+++ b/test/bt-utils.c
@@ -0,0 +1,223 @@
+/*
+ * BIRD Test -- Utils for testing parsing configuration file
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "nest/bird.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+
+#include "sysdep/unix/unix.h"
+#include "sysdep/unix/krt.h"
+
+#include "nest/iface.h"
+#include "nest/locks.h"
+
+#include "filter/filter.h"
+
+#define BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c)))
+
+static const byte *bt_config_parse_pos;
+static uint bt_config_parse_remain_len;
+
+/* This is cf_read_hook for hard-coded text configuration */
+static int
+cf_static_read(byte *dest, uint max_len, int fd UNUSED)
+{
+ if (max_len > bt_config_parse_remain_len)
+ max_len = bt_config_parse_remain_len;
+ memcpy(dest, bt_config_parse_pos, max_len);
+ bt_config_parse_pos += max_len;
+ bt_config_parse_remain_len -= max_len;
+ return max_len;
+}
+
+/* This is cf_read_hook for reading configuration files,
+ * function is copied from main.c, cf_read() */
+static int
+cf_file_read(byte *dest, uint max_len, int fd)
+{
+ int l = read(fd, dest, max_len);
+ if (l < 0)
+ cf_error("Read error");
+ return l;
+}
+
+void
+bt_bird_init(void)
+{
+ if(bt_verbose)
+ log_init_debug("");
+ log_switch(bt_verbose != 0, NULL, NULL);
+
+ resource_init();
+ olock_init();
+ io_init();
+ rt_init();
+ if_init();
+ config_init();
+
+ protos_build();
+ proto_build(&proto_unix_kernel);
+ proto_build(&proto_unix_iface);
+}
+
+void bt_bird_cleanup(void)
+{
+ for (int i = 0; i < EAP_MAX; i++)
+ attr_class_to_protocol[i] = NULL;
+
+ config = new_config = NULL;
+}
+
+static char *
+bt_load_file(const char *filename, int quiet)
+{
+ FILE *f = fopen(filename, "rb");
+ if (!quiet)
+ bt_assert_msg(f != NULL, "Open %s", filename);
+
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ long file_size_ = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if (file_size_ < 0)
+ return NULL;
+
+ size_t file_size = file_size_;
+ size_t read_size = 0;
+
+ char *file_body = mb_allocz(&root_pool, file_size+1);
+
+ /* XXX: copied from cf-lex.c */
+ errno=0;
+ while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f))
+ {
+ bt_debug("iteration \n");
+ if(errno != EINTR)
+ {
+ bt_abort_msg("errno: %d", errno);
+ break;
+ }
+ errno=0;
+ clearerr(f);
+ }
+ fclose(f);
+
+ if (!quiet)
+ bt_assert_msg(read_size == file_size, "Read %s", filename);
+
+ return file_body;
+}
+
+static void
+bt_show_cfg_error(const struct config *cfg)
+{
+ int lino = 0;
+ int lino_delta = 5;
+ int lino_err = cfg->err_lino;
+
+ const char *str = bt_load_file(cfg->err_file_name, 1);
+
+ while (str && *str)
+ {
+ lino++;
+ if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
+ bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " "));
+ do
+ {
+ if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
+ bt_debug("%c", *str);
+ } while (*str && *(str++) != '\n');
+ }
+ bt_debug("\n");
+}
+
+static struct config *
+bt_config_parse__(struct config *cfg)
+{
+ bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name);
+
+ if (cfg->err_msg)
+ {
+ bt_debug("Parse error %s, line %d: %s\n", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
+ bt_show_cfg_error(cfg);
+ return NULL;
+ }
+
+ config_commit(cfg, RECONFIG_HARD, 0);
+ new_config = cfg;
+
+ return cfg;
+}
+
+struct config *
+bt_config_parse(const char *cfg_str)
+{
+ struct config *cfg = config_alloc("configuration");
+
+ bt_config_parse_pos = cfg_str;
+ bt_config_parse_remain_len = strlen(cfg_str);
+ cf_read_hook = cf_static_read;
+
+ return bt_config_parse__(cfg);
+}
+
+struct config *
+bt_config_file_parse(const char *filepath)
+{
+ struct config *cfg = config_alloc(filepath);
+
+ cfg->file_fd = open(filepath, O_RDONLY);
+ bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath);
+ if (cfg->file_fd < 0)
+ return NULL;
+
+ cf_read_hook = cf_file_read;
+
+ return bt_config_parse__(cfg);
+}
+
+/*
+ * Returns @base raised to the power of @power.
+ */
+uint
+bt_naive_pow(uint base, uint power)
+{
+ uint result = 1;
+ uint i;
+ for (i = 0; i < power; i++)
+ result *= base;
+ return result;
+}
+
+/**
+ * bytes_to_hex - transform data into hexadecimal representation
+ * @buf: preallocated string buffer
+ * @in_data: data for transformation
+ * @size: the length of @in_data
+ *
+ * This function transforms @in_data of length @size into hexadecimal
+ * representation and writes it into @buf.
+ */
+void
+bt_bytes_to_hex(char *buf, const byte *in_data, size_t size)
+{
+ size_t i;
+ for(i = 0; i < size; i++)
+ sprintf(buf + i*2, "%02x", in_data[i]);
+}
+
diff --git a/test/bt-utils.h b/test/bt-utils.h
new file mode 100644
index 00000000..13d267cc
--- /dev/null
+++ b/test/bt-utils.h
@@ -0,0 +1,35 @@
+/*
+ * BIRD Test -- Utils for testing parsing configuration file
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRDTEST_UTILS_H_
+#define _BIRDTEST_UTILS_H_
+
+#include "sysdep/config.h"
+
+#define PRIip4 "%d.%d.%d.%d"
+#define ARGip4(x) (_I(x) >> 24) & 0xff, (_I(x) >> 16) & 0xff, (_I(x) >> 8) & 0xff, _I(x) & 0xff
+
+#define PRIip6 "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X"
+#define ARGip6_HIGH(x,i) (((x).addr[(i)] >> 16) & 0xffff)
+#define ARGip6_LOW(x,i) ((x).addr[(i)] & 0xffff)
+#define ARGip6_BOTH(x,i) ARGip6_HIGH(x,i), ARGip6_LOW(x,i)
+#define ARGip6(x) ARGip6_BOTH((x), 0), ARGip6_BOTH((x), 1), ARGip6_BOTH((x), 2), ARGip6_BOTH((x), 3)
+
+#define BT_CONFIG_PARSE_ROUTER_ID "router id 1.1.1.1; \n"
+#define BT_CONFIG_PARSE_STATIC_PROTO "protocol static { ipv4; } \n"
+#define BT_CONFIG_SIMPLE BT_CONFIG_PARSE_ROUTER_ID BT_CONFIG_PARSE_STATIC_PROTO
+
+uint bt_naive_pow(uint base, uint power);
+void bt_bytes_to_hex(char *buf, const byte *in_data, size_t size);
+
+void bt_bird_init(void);
+void bt_bird_cleanup(void);
+struct config *bt_config_parse(const char *cfg);
+struct config *bt_config_file_parse(const char *filepath);
+
+#endif /* _BIRDTEST_UTILS_H_ */