From 4ab98f62e913718da46b13ff9aa820564b2c2389 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 5 Feb 2016 09:52:46 +0100 Subject: [PATCH] test: add support for unit testing --- Makefile.in | 1 + configure | 2 +- test/unit/Makefile.in | 42 +++++++++++++++ test/unit/test.c | 119 ++++++++++++++++++++++++++++++++++++++++++ test/unit/test.h | 41 +++++++++++++++ 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 test/unit/Makefile.in create mode 100644 test/unit/test.c create mode 100644 test/unit/test.h diff --git a/Makefile.in b/Makefile.in index 6ac0c9e..c87f67f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -120,6 +120,7 @@ install: chronyd chronyc $(CC) $(CFLAGS) $(CPPFLAGS) -S $< check : chronyd chronyc + $(MAKE) -C test/unit check cd test/simulation && ./run install-docs : docs diff --git a/configure b/configure index 8608c8d..144e30d 100755 --- a/configure +++ b/configure @@ -848,7 +848,7 @@ fi add_def CHRONY_VERSION "\"${CHRONY_VERSION}\"" -for f in Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8 +for f in Makefile test/unit/Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8 do echo Creating $f sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\ diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in new file mode 100644 index 0000000..5fd925c --- /dev/null +++ b/test/unit/Makefile.in @@ -0,0 +1,42 @@ +TEST_WRAPPER = +CHRONY_SRCDIR = ../.. + +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = -I$(CHRONY_SRCDIR) @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ @LIBS@ @EXTRA_LIBS@ + +SHARED_OBJS = test.o + +TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c))) +TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS))) + +FILTER_OBJS = %/main.o %/client.o %/getdate.o +CHRONY_OBJS := $(filter-out $(FILTER_OBJS),$(wildcard $(CHRONY_SRCDIR)/*.o)) + +all: $(TESTS) + +%.test: %.o $(SHARED_OBJS) + $(CC) $(CFLAGS) -o $@ $^ $(CHRONY_OBJS:%/$*.o=) $(LDFLAGS) + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< + +check: $(TESTS) + @ret=0; \ + for t in $^; do \ + $(TEST_WRAPPER) ./$$t || ret=1; \ + done; \ + exit $$ret + +clean: + rm -f *.o $(TESTS) + rm -rf .deps + +.deps: + @mkdir .deps + +.deps/%.d: %.c | .deps + @$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@ + +-include $(TEST_OBJS:%.o=.deps/%.d) diff --git a/test/unit/test.c b/test/unit/test.c new file mode 100644 index 0000000..1a7bc4a --- /dev/null +++ b/test/unit/test.c @@ -0,0 +1,119 @@ +/* + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + */ + +#include +#include +#include + +#include "test.h" + +void +test_fail(int line) +{ + printf("FAIL (on line %d)\n", line); + exit(1); +} + +int +main(int argc, char **argv) +{ + char *test_name, *s; + int i, seed = 0; + + test_name = argv[0]; + s = strrchr(test_name, '.'); + if (s) + *s = '\0'; + s = strrchr(test_name, '/'); + if (s) + test_name = s + 1; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d")) { + LOG_SetDebugLevel(2); + } else if (!strcmp(argv[i], "-s") && i + 1 < argc) { + seed = atoi(argv[++i]); + } else { + fprintf(stderr, "Unknown option\n"); + exit(1); + } + } + + srandom(seed ? seed : time(NULL)); + + printf("Testing %-30s ", test_name); + fflush(stdout); + + test_unit(); + + printf("PASS\n"); + + return 0; +} + +void +get_random_address(IPAddr *ip, int family, int bits) +{ + if (family != IPADDR_INET4 && family != IPADDR_INET6) + family = random() % 2 ? IPADDR_INET4 : IPADDR_INET6; + + ip->family = family; + + if (family == IPADDR_INET4) { + if (bits < 0) + bits = 32; + assert(bits <= 32); + + if (bits > 16) + ip->addr.in4 = (uint32_t)random() % (1U << (bits - 16)) << 16 | + (uint32_t)random() % (1U << 16); + else + ip->addr.in4 = (uint32_t)random() % (1U << bits); + } else { + int i, b; + + if (bits < 0) + bits = 128; + assert(bits <= 128); + + for (i = 0, b = 120; i < 16; i++, b -= 8) { + if (b >= bits) { + ip->addr.in6[i] = 0; + } else { + ip->addr.in6[i] = random() % (1U << MIN(bits - b, 8)); + } + } + } +} + +void +swap_address_bit(IPAddr *ip, unsigned int b) +{ + if (ip->family == IPADDR_INET4) { + assert(b < 32); + ip->addr.in4 ^= 1U << (31 - b); + } else if (ip->family == IPADDR_INET6) { + assert(b < 128); + ip->addr.in6[b / 8] ^= 1U << (7 - b % 8); + } else { + assert(0); + } +} + diff --git a/test/unit/test.h b/test/unit/test.h new file mode 100644 index 0000000..d1e83cb --- /dev/null +++ b/test/unit/test.h @@ -0,0 +1,41 @@ +/* + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + */ + +#ifndef GOT_TEST_H +#define GOT_TEST_H + +#include + +extern void test_unit(void); + +#define TEST_CHECK(expr) \ + do { \ + if (!(expr)) { \ + test_fail(__LINE__); \ + exit(1); \ + } \ + } while (0) + +extern void test_fail(int line); + +extern void get_random_address(IPAddr *ip, int family, int bits); +extern void swap_address_bit(IPAddr *ip, unsigned int b); + +#endif