diff --git a/apps/unit-test/Makefile.unit-test b/apps/unit-test/Makefile.unit-test new file mode 100644 index 000000000..92402f589 --- /dev/null +++ b/apps/unit-test/Makefile.unit-test @@ -0,0 +1 @@ +unit-test_src = unit-test.c diff --git a/apps/unit-test/example-test.c b/apps/unit-test/example-test.c new file mode 100644 index 000000000..ea19dedbb --- /dev/null +++ b/apps/unit-test/example-test.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science + * All rights reserved. + * + * 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 THE INSTITUTE 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. + */ + +/** + * \file + * A test program for the unit test library. + * \author + * Nicolas Tsiftes + */ + +#include "contiki.h" +#include "unit-test.h" + +UNIT_TEST_REGISTER(arithmetic, "Arith ops"); +UNIT_TEST_REGISTER(string, "String ops"); + +UNIT_TEST(arithmetic) +{ + int a, b; + + UNIT_TEST_BEGIN(); + + a = 1; + b = 2; + + UNIT_TEST_ASSERT(a + b == 3); + + UNIT_TEST_END(); +} + +UNIT_TEST(string) +{ + char str1[] = "A"; + + UNIT_TEST_BEGIN(); + + UNIT_TEST_ASSERT(str1[0] == 'B'); + + UNIT_TEST_END(); +} + +PROCESS(test_process, "Unit testing"); +AUTOSTART_PROCESSES(&test_process); + +PROCESS_THREAD(test_process, ev, data) +{ + PROCESS_BEGIN(); + + UNIT_TEST_RUN(arithmetic); + UNIT_TEST_RUN(string); + + PROCESS_END(); +} diff --git a/apps/unit-test/unit-test.c b/apps/unit-test/unit-test.c new file mode 100644 index 000000000..60c5da78c --- /dev/null +++ b/apps/unit-test/unit-test.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science + * All rights reserved. + * + * 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 THE INSTITUTE 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. + */ + +/** + * \file + * A tool for unit testing Contiki software. + * \author + * Nicolas Tsiftes + */ + +#include + +#include "unit-test.h" + +/*---------------------------------------------------------------------------*/ +/** + * Print the results of a unit test. + * + * \param utp The unit test descriptor. + */ +void +unit_test_print_report(const unit_test_t *utp) +{ + printf("\nUnit test: %s\n", utp->descr); + printf("Result: %s\n", utp->result == unit_test_failure ? + "failure" : "success"); + printf("Exit point: %s:%u\n", utp->test_file, utp->exit_line); + printf("Start: %u\n", utp->start); + printf("End: %u\n", utp->end); + printf("Duration: %u\n", utp->end - utp->start); + printf("Ticks per second: %u\n", RTIMER_SECOND); +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/unit-test/unit-test.h b/apps/unit-test/unit-test.h new file mode 100644 index 000000000..244b8b451 --- /dev/null +++ b/apps/unit-test/unit-test.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science + * All rights reserved. + * + * 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 THE INSTITUTE 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. + */ + +/** + * \file + * A tool for unit testing Contiki software. + * \author + * Nicolas Tsiftes + */ + +#ifndef UNIT_TEST_H +#define UNIT_TEST_H + +#include "sys/rtimer.h" + +typedef enum unit_test_result { + unit_test_failure = 0, + unit_test_success = 1 +} unit_test_result_t; + +typedef struct unit_test { + const char * const descr; + unit_test_result_t result; + const char *test_file; + unsigned exit_line; + rtimer_clock_t start; + rtimer_clock_t end; +} unit_test_t; + +/** + * Register a unit test. + * + * This macro allocates unit test descriptor, which is a structure of + * type unit_test_t. The descriptor contains information about a unit + * test, and the results from the last execution of the test. + * + * \param name The name of the unit test. + * \param descr A string that briefly describes the unit test. + */ +#define UNIT_TEST_REGISTER(name, descr) static unit_test_t unit_test_##name = {descr, unit_test_success, __FILE__, 0, 0, 0} + +/** + * Define a unit test. + * + * This macro defines the function that will be executed when conducting + * a unit test. The name that is passed as a parameter must have been + * registered with the UNIT_TEST_REGISTER() macro. + * + * The function defined by this macro must start with a call to the + * UNIT_TEST_BEGIN() macro, and end with a call to the UNIT_TEST_END() + * macro. + * + * The standard test function template produced by this macro will + * ensure that the unit test keeps track of the result, the time taken to + * execute (in rtimer ticks), and the exit point of the test. The + * latter corresponds to the line number at which the test was + * determined to be a success or failure. + * + * \param name The name of the unit test. + */ +#define UNIT_TEST(name) unit_test_result_t unit_test_function_##name(unit_test_t *utp) + +/** + * Mark the starting point of the unit test function. + */ +#define UNIT_TEST_BEGIN() do { \ + utp->start = RTIMER_NOW(); \ + utp->result = unit_test_success; \ + } while(0) + +/** + * Mark the ending point of the unit test function. + */ +#define UNIT_TEST_END() UNIT_TEST_SUCCEED(); \ + unit_test_end: \ + utp->end = RTIMER_NOW(); \ + return utp->result; + +/* + * The test result is printed with a function that is selected by + * defining UNIT_TEST_PRINT_FUNCTION, which must be of the type + * "void (*)(const unit_test_t *)". The default selection is + * unit_test_print_report, which is available in unit-test.c. + */ +#ifndef UNIT_TEST_PRINT_FUNCTION +#define UNIT_TEST_PRINT_FUNCTION unit_test_print_report +#endif /* !UNIT_TEST_PRINT_FUNCTION */ + +/** + * Print a report of the execution of a unit test. + * + * \param name The name of the unit test. + */ +#define UNIT_TEST_PRINT_REPORT(name) UNIT_TEST_PRINT_FUNCTION(&unit_test_##name); + +/** + * Execute a unit test. + * + * \param name The name of the unit test. + */ +#define UNIT_TEST_RUN(name) unit_test_function_##name(&unit_test_##name); UNIT_TEST_PRINT_REPORT(name); + +/** + * Report that a unit test succeeded. + * + * This macro is useful for writing tests that can succeed earlier than + * the last execution point of the test, which is specified by a call to + * the UNIT_TEST_END() macro. + * + * Tests can usually be written without calls to UNIT_TEST_SUCCEED(), + * since it is implicitly called at the end of the test---unless + * UNIT_TEST_FAIL() has been called. + * + */ +#define UNIT_TEST_SUCCEED() do { \ + utp->exit_line = __LINE__; \ + goto unit_test_end; \ + } while(0) + +/** + * Report that a unit test failed. + * + * This macro is used to signal that a unit test failed to execute. The + * line number at which this macro was called is stored in the unit test + * descriptor. + */ +#define UNIT_TEST_FAIL() do { \ + utp->exit_line = __LINE__; \ + utp->result = unit_test_failure; \ + goto unit_test_end; \ + } while(0) + +/** + * Report failure if an expression is false. + * + * \param expr The expression to evaluate. + */ +#define UNIT_TEST_ASSERT(expr) do { \ + if(!(expr)) { \ + UNIT_TEST_FAIL(); \ + } \ + } while(0) + +void unit_test_print_report(const unit_test_t *utp); + +#endif /* !UNIT_TEST_H */