]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Unit Testing for BIRD
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 9 Nov 2016 15:36:34 +0000 (16:36 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 9 Nov 2016 15:36:34 +0000 (16:36 +0100)
 - 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.

60 files changed:
Makefile.in
conf/Makefile
conf/conf.c
conf/conf.h
configure.in
doc/bird.sgml
filter/Makefile
filter/config.Y
filter/filter.c
filter/filter.h
filter/filter_test.c [new file with mode: 0644]
filter/test.conf
filter/test.conf.inc
filter/test.conf2
filter/test6.conf
filter/test_bgp_filtering.conf [new file with mode: 0644]
filter/tree_test.c [new file with mode: 0644]
filter/trie_test.c [new file with mode: 0644]
lib/Makefile
lib/birdlib.h
lib/bitops.h
lib/bitops_test.c [new file with mode: 0644]
lib/buffer_test.c [new file with mode: 0644]
lib/checksum_test.c [new file with mode: 0644]
lib/event_test.c [new file with mode: 0644]
lib/fletcher16_test.c [new file with mode: 0644]
lib/hash_test.c [new file with mode: 0644]
lib/heap_test.c [new file with mode: 0644]
lib/ip.c
lib/ip_test.c [new file with mode: 0644]
lib/lists_test.c [new file with mode: 0644]
lib/mac_test.c [new file with mode: 0644]
lib/patmatch_test.c [new file with mode: 0644]
lib/printf_test.c [new file with mode: 0644]
lib/slist_test.c [new file with mode: 0644]
lib/slists.c
nest/Makefile
nest/a-path.c
nest/a-path_test.c [new file with mode: 0644]
nest/a-set_test.c [new file with mode: 0644]
nest/iface.h
nest/route.h
proto/bfd/Makefile
proto/bgp/Makefile
proto/ospf/Makefile
proto/ospf/rt.c
proto/pipe/Makefile
proto/radv/Makefile
proto/radv/radv.c
proto/rip/Makefile
proto/static/Makefile
sysdep/autoconf.h.in
sysdep/bsd/Makefile
sysdep/linux/Makefile
sysdep/unix/Makefile
test/Makefile [new file with mode: 0644]
test/birdtest.c [new file with mode: 0644]
test/birdtest.h [new file with mode: 0644]
test/bt-utils.c [new file with mode: 0644]
test/bt-utils.h [new file with mode: 0644]

index cee217be9480ae5c34239b13f19b760a48747c8c..63d3351fbb7fe1f7c819c1438727433f56a6f3cd 100644 (file)
@@ -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)
index e5828538d58719512e85590f8c58fd035373bd1d..cc2b13c6e0fbeac2f81bffcc9218a4601de55ccc 100644 (file)
@@ -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
index b6f41b2c635b68e1eab5a07a373be8599e6c58da..3ae85cb233ec68251c94163eb1c6f4606dd0db64 100644 (file)
 #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;
index 593a5f1326cbad38564ba6ef62056e2ac8118332..cb5ade47c36c5caa42d51be9a76c7b35736a3167 100644 (file)
@@ -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 */
index 58f865c4c51e766178c8e95041f65b5bb2751407..912598b8e9c9235d6eaeb056d1a519f4c53b1c89 100644 (file)
@@ -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
index 6af0e0f6791b65712e2cc2960f9f1ea78babfb99..e70232d1b8fbc1edaa154a132c02d3cd43048f3b 100644 (file)
@@ -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;/
index f27befdf85528ac3da064c57992f7371864954bf..6bada8cac6a0d4aa12f8a10ee8019ab3e5475c5d 100644 (file)
@@ -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)
index 8af444a3b36a1609f3a20dc079e5a2003edbcf84..b5ae850ac34735bb7d9107aa110dbefc760c74d1 100644 (file)
@@ -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
index 09b89401a2b6461e369f9a8b8e686af3dc2e9f8d..3df602a30edd5eb82ff25a048a62d022a7bf4a1c 100644 (file)
@@ -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);
index fc11b91eb8cbf7abb5a432df8bc51201ab2da755..a4808731e37bbdea233c408a307640b088696173 100644 (file)
 
 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 (file)
index 0000000..693b1fe
--- /dev/null
@@ -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();
+}
index e65b3ebbaea6d84734f55362047b26b27200506c..de3a31130aa076c8b3340859fcaaf34f03cd39a8 100644 (file)
@@ -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
index 109a49c53262dcea6479de55561b071f10732def..7707ae3850b3b187d35ba73e741c987588da5c2a 100644 (file)
@@ -2,4 +2,5 @@
 print "Entering include";
 print "Should be 2:  ", 1+1;
 print "Leaving include";
+i = 42;
 
index 60bdd9653f8fc474765cdbaa03551241e748d9f6..2a5d896bdd94308882d3b8edcd749aa55ca39901 100644 (file)
@@ -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";
 }
index f25ffc4709f9131bf2357697b1925cbf9bf605ff..fb82cf6b125d152f3d357b3cf41402c18a427c28 100644 (file)
@@ -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 (file)
index 0000000..573cad4
--- /dev/null
@@ -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 (file)
index 0000000..abe955d
--- /dev/null
@@ -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 (file)
index 0000000..c528c7d
--- /dev/null
@@ -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();
+}
index 551089c3bc60a8fa723c37e8c2eb87d70017ecb1..26d8bf657cdfac2dbaf1727fc5a8f7a4c52abf68 100644 (file)
@@ -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)
index ddc963f4776d6a8a958f35bab6cab39b0e396c8b..c352b7f69ce880a86c1409bde4d6ae33ff33e9af 100644 (file)
@@ -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 */
 
index 9f954374597240694667e7b8046715db98132d3d..af648c268e1e8fc9d9daeb63145985188af39d78 100644 (file)
@@ -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 (file)
index 0000000..bd02fcc
--- /dev/null
@@ -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 (file)
index 0000000..38e540b
--- /dev/null
@@ -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 (file)
index 0000000..ae5a7f3
--- /dev/null
@@ -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 (file)
index 0000000..1997344
--- /dev/null
@@ -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 (file)
index 0000000..3e03690
--- /dev/null
@@ -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 (file)
index 0000000..07607f6
--- /dev/null
@@ -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 (file)
index 0000000..40c9dd8
--- /dev/null
@@ -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();
+}
index 5e039c12c65cedaa02b34bf81bcfd759341f95d1..9497248c3a1dacb82c1b7c3258cadf2757da400f 100644 (file)
--- 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 (file)
index 0000000..81b4897
--- /dev/null
@@ -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 (file)
index 0000000..56cc842
--- /dev/null
@@ -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 (file)
index 0000000..8522f95
--- /dev/null
@@ -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 (file)
index 0000000..b2b4cb9
--- /dev/null
@@ -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 (file)
index 0000000..9763b7b
--- /dev/null
@@ -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 (file)
index 0000000..fd0b1ca
--- /dev/null
@@ -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();
+}
index 6e0df39e196e9bd6cb745fc07282de010a9e0184..00f3c84f48ed35e24ecba554374d012a80a8e7b6 100644 (file)
@@ -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
index 6f0f9a08f88554242f64baa8453732a8da0b5576..d673cee581a65d0473a48e57165d35d9bc197331 100644 (file)
@@ -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)
index b453f702099e8dce770c6e1b890a74b077152d77..bc2216a051749ff61888182410caee295c773b39 100644 (file)
@@ -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 (file)
index 0000000..2dc46db
--- /dev/null
@@ -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 (file)
index 0000000..763b6b9
--- /dev/null
@@ -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();
+}
index c4f414ece3a826299ac1e43286910e9c1f21a1e1..d960b859c692c9b4988e60d881c587d24059bb2c 100644 (file)
@@ -10,6 +10,7 @@
 #define _BIRD_IFACE_H_
 
 #include "lib/lists.h"
+#include "lib/ip.h"
 
 extern list iface_list;
 
index f2e883b60d5bbd96275cb05a3fbe729f9e00570b..5104d8f1263d320b22e5e2871ebc65668b86e0ca 100644 (file)
@@ -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;
index 489216d8ef3b6d0fa54940e775f5ee13e010c32a..402122fc37804e42ca24dc43f60d2ddea40767af 100644 (file)
@@ -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
index f49588679aaf44ed44cd6bd9687cb1f8f7170f9f..00aaef5e123a68a5282ed3d435c8fbad9d66fc97 100644 (file)
@@ -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
index fe52ed301200bf07525cfbdfbcd25109b5adff3c..39e74f719413d994345d8c6875de092cc6c66952 100644 (file)
@@ -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
index c5c547839d77564f571f4bb3debcdafa67fb4f14..054841caa58e70e22306b75ad90fbd463dbda7aa 100644 (file)
@@ -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);
index c258a3e5baadcc9882393eef8494b1bd8b03c87a..5093da98e38f7a8aecb084fc39e777db469bdfaf 100644 (file)
@@ -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
index 3584a5f30dd81440ffacf946caac3a1a422a366f..05317eff20c65b573da6d1a40728ce27f1e9145b 100644 (file)
@@ -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
index 44b44879a0066ebe8b96655ba5c499bdb19a78a1..d7d975abc9b5d6572632556f6a17d537d0ea6209 100644 (file)
@@ -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);
 }
 
index 6e645cc2fe8424f88c028b7ec3dabf10e3c1e3d7..7feabcd8b051784e595a41df3fc694ac174f5536 100644 (file)
@@ -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
index 3ace39cf3c03a882c76e267102b2ff2547a8c02b..e38f9b741ba5176bf077311e256d4168b4bbb58f 100644 (file)
@@ -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
index c73270c39100879440768d9696ca3b9c4b6fdda6..0d0627f3079222a8e154b48e1bed0115a63bc08b 100644 (file)
@@ -67,4 +67,7 @@
 /* We have stdint.h */
 #undef HAVE_STDINT_H
 
+/* We have execinfo.h */
+#undef HAVE_EXECINFO_H
+
 #define CONFIG_PATH ?
index ddc8723982a1be30eba310e82346786c2794ab90..dfa32747af12c39a2d98793873f8750fa6cd9e30 100644 (file)
@@ -3,3 +3,4 @@ obj := $(src-o-files)
 $(all-daemon)
 $(conf-y-targets): $(s)krt-sock.Y
 
+tests_objs := $(tests_objs) $(src-o-files)
index 23cf1d9dcdd479a7ab2b8773fce04498634f4a4c..188ac8de9c23d78f98c685576b0c296bd8d4e676 100644 (file)
@@ -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)
index c5d554310a0536a099b462792d27dcda6c90cd6c..f592399c1ba85c8cbda5b4c899301bfddd025942 100644 (file)
@@ -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 (file)
index 0000000..2cee923
--- /dev/null
@@ -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 (file)
index 0000000..4e8645a
--- /dev/null
@@ -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 (file)
index 0000000..0090712
--- /dev/null
@@ -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 (file)
index 0000000..aaeb77b
--- /dev/null
@@ -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 (file)
index 0000000..13d267c
--- /dev/null
@@ -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_ */