From b620082e168c4b8b76f1ae6063123f6b2dcc70ec Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Thu, 14 Jun 2012 13:07:27 +0400 Subject: [PATCH] Implement a simple unit testing framework. Add the first unit test. Extend queue.h with STAILQ_SPLICE and STAILQ_REVERSE. Test the new functions in a simple unit testing framework. --- .gitignore | 1 + test/CMakeLists.txt | 1 + test/lib/server.py | 6 +- test/lib/unittest_server.py | 36 ++++++++ test/unit/CMakeLists.txt | 1 + test/unit/queue.c | 166 ++++++++++++++++++++++++++++++++++++ test/unit/queue.result | 37 ++++++++ test/unit/queue.test | 1 + test/unit/suite.ini | 10 +++ test/unit/unit.h | 35 ++++++++ third_party/queue.h | 25 ++++++ 11 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 test/lib/unittest_server.py create mode 100644 test/unit/CMakeLists.txt create mode 100644 test/unit/queue.c create mode 100644 test/unit/queue.result create mode 100644 test/unit/queue.test create mode 100644 test/unit/suite.ini create mode 100644 test/unit/unit.h diff --git a/.gitignore b/.gitignore index 1f82f83581..e7129f79d2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ test/lib/*.pyc test/lib/*/*.pyc test/box/protocol test/box/connector +test/unit/queue Makefile CMakeFiles CMakeCache.txt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ad52105be4..0d2a43e561 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,6 +4,7 @@ add_custom_target(test add_custom_target(test-force COMMAND ${PROJECT_SOURCE_DIR}/test/run.sh --builddir=${PROJECT_BINARY_DIR} --force --vardir=${PROJECT_BINARY_DIR}/test/var) +add_subdirectory(unit) add_subdirectory(box) add_subdirectory(connector_c) diff --git a/test/lib/server.py b/test/lib/server.py index 2c2590d08e..5730ffe979 100644 --- a/test/lib/server.py +++ b/test/lib/server.py @@ -177,7 +177,7 @@ class Server(object): if start_and_exit != None: self.start_and_exit = start_and_exit if gdb != None: self.gdb = gdb if valgrind != None: self.valgrind = valgrind - self.debug = self.test_debug() + self.debug = self.test_debug() if self.is_started: if not silent: @@ -269,7 +269,7 @@ class Server(object): def test_option_get(self, show, option_list_str): args = [self.binary] + option_list_str.split() - if show: + if show: print " ".join([os.path.basename(self.binary)] + args[1:]) output = subprocess.Popen(args, cwd = self.vardir, @@ -282,7 +282,7 @@ class Server(object): def test_debug(self): output = self.test_option_get(False, "-V") - if re.search("-Debug", output): + if re.search("-Debug", output): return True return False diff --git a/test/lib/unittest_server.py b/test/lib/unittest_server.py new file mode 100644 index 0000000000..5d56bbc7f0 --- /dev/null +++ b/test/lib/unittest_server.py @@ -0,0 +1,36 @@ +from server import Server +import subprocess +import sys +import os + +class UnittestServer(Server): + """A dummy server implementation for unit test suite""" + def __new__(cls, core="unittest", module="dummy"): + return Server.__new__(cls) + + + def __init__(self, core="unittest", module="dummy"): + Server.__init__(self, core, module) + self.debug = False + + def configure(self, config): + pass + def deploy(self, config=None, binary=None, vardir=None, + mem=None, start_and_exit=None, gdb=None, valgrind=None, + valgrind_sup=None, init_lua=None, silent=True, need_init=True): + self.vardir = vardir + def run_test(name): + p = subprocess.Popen([os.path.join(self.builddir, "test/unit", name)], stdout=subprocess.PIPE) + p.wait() + for line in p.stdout.readlines(): + sys.stdout.write(line) + + self.run_test = run_test + + def start(self): + pass + def find_exe(self, builddir, silent=False): + self.builddir = builddir + + def init(self): + pass diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt new file mode 100644 index 0000000000..a2961e1ba7 --- /dev/null +++ b/test/unit/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(queue queue.c) diff --git a/test/unit/queue.c b/test/unit/queue.c new file mode 100644 index 0000000000..5fbfdeeff7 --- /dev/null +++ b/test/unit/queue.c @@ -0,0 +1,166 @@ +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "third_party/queue.h" +#include "unit.h" +#include <stdio.h> +#include <assert.h> + +struct elem +{ + STAILQ_ENTRY(elem) entry; + int val; +}; + +STAILQ_HEAD(elem_queue, elem); + +const char * +queue2str(struct elem_queue *queue) +{ + static char buf[1024]; + buf[0] = '\0'; + struct elem *elem; + int n = 0; + STAILQ_FOREACH(elem, queue, entry) { + n += snprintf(buf + n, sizeof(buf) - n - 1, "%d ", elem->val); + } + return buf; +} + +/** Test a queue with 0 elements. */ +void test0() +{ + header(); + struct elem_queue queue = STAILQ_HEAD_INITIALIZER(queue); + printf("Initialized: %s\n", queue2str(&queue)); + STAILQ_INIT(&queue); + printf("STAILQ_INIT: %s\n", queue2str(&queue)); + STAILQ_REVERSE(&queue, elem, entry); + printf("STAILQ_REVERSE: %s\n", queue2str(&queue)); + footer(); +} + +/** Test a queue with 1 element. */ +void test1() +{ + header(); + struct elem el1; + struct elem_queue queue = STAILQ_HEAD_INITIALIZER(queue); + el1.val = 1; + STAILQ_INSERT_TAIL(&queue, &el1, entry); + printf("STAILQ_INIT: %s\n", queue2str(&queue)); + STAILQ_REVERSE(&queue, elem, entry); + printf("STAILQ_REVERSE: %s\n", queue2str(&queue)); + footer(); +} + + +void test2() +{ + header(); + struct elem el1, el2; + struct elem_queue queue = STAILQ_HEAD_INITIALIZER(queue); + el1.val = 1; + el2.val = 2; + STAILQ_INSERT_TAIL(&queue, &el1, entry); + STAILQ_INSERT_TAIL(&queue, &el2, entry); + printf("STAILQ_INIT: %s\n", queue2str(&queue)); + STAILQ_REVERSE(&queue, elem, entry); + printf("STAILQ_REVERSE: %s\n", queue2str(&queue)); + footer(); +} + +void test3() +{ + header(); + struct elem el1, el2, el3; + struct elem_queue queue = STAILQ_HEAD_INITIALIZER(queue); + el1.val = 1; + el2.val = 2; + el3.val = 3; + STAILQ_INSERT_TAIL(&queue, &el1, entry); + STAILQ_INSERT_TAIL(&queue, &el2, entry); + STAILQ_INSERT_TAIL(&queue, &el3, entry); + printf("STAILQ_INIT: %s\n", queue2str(&queue)); + STAILQ_REVERSE(&queue, elem, entry); + printf("STAILQ_REVERSE: %s\n", queue2str(&queue)); + footer(); +} + + +void test_splice() +{ + header(); + struct elem el1, el2, el3; + struct elem_queue queue1 = STAILQ_HEAD_INITIALIZER(queue1); + struct elem_queue queue2 = STAILQ_HEAD_INITIALIZER(queue2); + STAILQ_SPLICE(&queue1, STAILQ_FIRST(&queue1), entry, &queue2); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue2, STAILQ_FIRST(&queue2), entry, &queue1); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + el1.val = 1; + el2.val = 2; + el3.val = 3; + STAILQ_INSERT_TAIL(&queue1, &el1, entry); + STAILQ_INSERT_TAIL(&queue1, &el2, entry); + STAILQ_INSERT_TAIL(&queue1, &el3, entry); + printf("STAILQ_INIT: %s\n", queue2str(&queue1)); + STAILQ_SPLICE(&queue1, STAILQ_FIRST(&queue1), entry, &queue2); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue2, STAILQ_FIRST(&queue2), entry, &queue1); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue1, STAILQ_NEXT(STAILQ_FIRST(&queue1), entry), + entry, &queue2); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue2, STAILQ_NEXT(STAILQ_FIRST(&queue2), entry), + entry, &queue1); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue2, STAILQ_FIRST(&queue2), entry, &queue1); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + STAILQ_SPLICE(&queue2, STAILQ_FIRST(&queue2), entry, &queue1); + printf("q1: %s\n", queue2str(&queue1)); + printf("q2: %s\n", queue2str(&queue2)); + footer(); +} + +int main() +{ + test0(); + test1(); + test2(); + test3(); + test_splice(); + return 0; +} diff --git a/test/unit/queue.result b/test/unit/queue.result new file mode 100644 index 0000000000..9839056432 --- /dev/null +++ b/test/unit/queue.result @@ -0,0 +1,37 @@ + *** test0 *** +Initialized: +STAILQ_INIT: +STAILQ_REVERSE: + *** test0: done *** + *** test1 *** +STAILQ_INIT: 1 +STAILQ_REVERSE: 1 + *** test1: done *** + *** test2 *** +STAILQ_INIT: 1 2 +STAILQ_REVERSE: 2 1 + *** test2: done *** + *** test3 *** +STAILQ_INIT: 1 2 3 +STAILQ_REVERSE: 3 2 1 + *** test3: done *** + *** test_splice *** +q1: +q2: +q1: +q2: +STAILQ_INIT: 1 2 3 +q1: +q2: 1 2 3 +q1: 1 2 3 +q2: +q1: 1 +q2: 2 3 +q1: 1 3 +q2: 2 +q1: 1 3 2 +q2: +q1: 1 3 2 +q2: + *** test_splice: done *** + \ No newline at end of file diff --git a/test/unit/queue.test b/test/unit/queue.test new file mode 100644 index 0000000000..78ef0b1753 --- /dev/null +++ b/test/unit/queue.test @@ -0,0 +1 @@ +run_test("queue") diff --git a/test/unit/suite.ini b/test/unit/suite.ini new file mode 100644 index 0000000000..47106bc06f --- /dev/null +++ b/test/unit/suite.ini @@ -0,0 +1,10 @@ +[default] +core = unittest +module = box +description = unit tests +config = tarantool.cfg +# put disabled tests here +#disabled = xlog.test +# put disabled in valgrind test here +#valgrind_disabled = admin_coredump.test +#release_disabled = errinj.test diff --git a/test/unit/unit.h b/test/unit/unit.h new file mode 100644 index 0000000000..64b133fc1f --- /dev/null +++ b/test/unit/unit.h @@ -0,0 +1,35 @@ +#ifndef INCLUDES_TARANTOOL_TEST_UNIT_H +#define INCLUDES_TARANTOOL_TEST_UNIT_H +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define header() printf("\t*** %s ***\n", __FUNCTION__) +#define footer() printf("\t*** %s: done ***\n ", __FUNCTION__) + +#endif /* INCLUDES_TARANTOOL_TEST_UNIT_H */ diff --git a/third_party/queue.h b/third_party/queue.h index 2112256024..0eead7407d 100644 --- a/third_party/queue.h +++ b/third_party/queue.h @@ -304,6 +304,31 @@ struct { \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0) +/* Reverse a list in-place. */ +#define STAILQ_REVERSE(head, type, member) do { \ + struct type *elem = STAILQ_FIRST(head), *next; \ + STAILQ_INIT(head); \ + while (elem) { \ + next = STAILQ_NEXT(elem, member); \ + STAILQ_INSERT_HEAD(head, elem, member); \ + elem = next; \ + } \ +} while (0) + +/* Concat all members of head1 starting from elem to the end of head2. */ +#define STAILQ_SPLICE(head1, elem, member, head2) do { \ + if (elem) { \ + *(head2)->stqh_last = (elem); \ + (head2)->stqh_last = (head1)->stqh_last; \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + while (*(head1)->stqh_last != (elem)) { \ + (head1)->stqh_last = &STAILQ_NEXT( \ + *(head1)->stqh_last, member); \ + } \ + *(head1)->stqh_last = NULL; \ + } \ +} while (0) + /* * List declarations. */ -- GitLab