diff --git a/tests/unittests/tests-cpp_ctors/Makefile b/tests/unittests/tests-cpp_ctors/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-cpp_ctors/Makefile.include b/tests/unittests/tests-cpp_ctors/Makefile.include new file mode 100644 index 0000000000..e355de5d71 --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/Makefile.include @@ -0,0 +1 @@ +FEATURES_REQUIRED += cpp diff --git a/tests/unittests/tests-cpp_ctors/README.md b/tests/unittests/tests-cpp_ctors/README.md new file mode 100644 index 0000000000..4d97868492 --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/README.md @@ -0,0 +1,18 @@ +The purpose of this test is to ensure that C++ constructors are executed +properly during the startup of RIOT. This requires that the port calls +constructors somewhere during C-library initialization. On newlib ports this is +done by __libc_init_array(), other ports may need to manually iterate through +the list of initializer functions (usually .init_array), and call each one in +order. + +There are three tests: + - Global constructor + - Static constructor + - Local constructor + +The global constructor test checks to see if the constructor of a global object +has been run during the boot process. The static constructor test does the +same, but for static object inside a function. The local constructor test checks +that a locally created object does have its constructor run. +The local constructor test will only fail if there is a significant problem with +the C++ tool chain, since it does not rely on any external C++ support code. diff --git a/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-class.cpp b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-class.cpp new file mode 100644 index 0000000000..f67781a683 --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-class.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016-2017 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include "tests-cpp_ctors.h" + +volatile long tests_cpp_ctors_magic1 = 12345; +volatile long tests_cpp_ctors_magic2 = 11111111; +void *tests_cpp_ctors_order[8]; + +namespace RIOTTestCPP { + +MyClass::MyClass() +{ + var = tests_cpp_ctors_magic1; +} + +MyClass::MyClass(long value) : var(value) +{ +} + +long MyClass::value() +{ + return var; +} + +void MyClass::inc() +{ + ++var; +} + +} /* namespace RIOTTestCPP */ diff --git a/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-trampoline.c b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-trampoline.c new file mode 100644 index 0000000000..ab98e75ea6 --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors-trampoline.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016-2017 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include "embUnit.h" +#include "embUnit/embUnit.h" +#include "tests-cpp_ctors.h" +#include "thread.h" /* For thread_getpid() */ + +long tests_cpp_ctors_global_value(void); +long tests_cpp_ctors_static_value(void); +long tests_cpp_ctors_local_value(long number); + +extern volatile long tests_cpp_ctors_magic1; +extern volatile long tests_cpp_ctors_magic2; +extern void *tests_cpp_ctors_order[8]; + +static void tests_cpp_global_ctors(void) +{ + long expected = tests_cpp_ctors_magic1; + long actual = tests_cpp_ctors_global_value(); + /* Test to ensure that global constructors have executed */ + TEST_ASSERT_EQUAL_INT(expected, actual); +} + +static void tests_cpp_static_ctors(void) +{ + for (long i = 1; i < 10; ++i) { + long expected = tests_cpp_ctors_magic2 + i; + long actual = tests_cpp_ctors_static_value(); + TEST_ASSERT_EQUAL_INT(expected, actual); + } +} + +static void tests_cpp_local_ctors(void) +{ + /* Test to ensure that local constructors are executed properly */ + long expected = thread_getpid() + 1; + long actual = tests_cpp_ctors_local_value(thread_getpid()); + TEST_ASSERT_EQUAL_INT(expected, actual); +} + +Test *tests_cpp_ctors_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(tests_cpp_local_ctors), + new_TestFixture(tests_cpp_global_ctors), + new_TestFixture(tests_cpp_static_ctors), + }; + + EMB_UNIT_TESTCALLER(cpp_tests, NULL, NULL, fixtures); + + return (Test *)&cpp_tests; +} + +void tests_cpp_ctors(void) +{ + TESTS_RUN(tests_cpp_ctors_tests()); +} diff --git a/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.cpp b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.cpp new file mode 100644 index 0000000000..81b3aa2bb7 --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016-2017 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include "tests-cpp_ctors.h" + +using RIOTTestCPP::MyClass; + +MyClass global_obj; + +extern "C" { +long tests_cpp_ctors_global_value(void); +long tests_cpp_ctors_static_value(void); +long tests_cpp_ctors_local_value(long); +} +extern volatile long tests_cpp_ctors_magic2; + +long tests_cpp_ctors_local_value(long number) { + MyClass local_obj(number); + local_obj.inc(); + return local_obj.value(); +} + +long tests_cpp_ctors_static_value() { + static MyClass static_obj(tests_cpp_ctors_magic2); + static_obj.inc(); + + return static_obj.value(); +} + +long tests_cpp_ctors_global_value() { + return global_obj.value(); +} diff --git a/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.h b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.h new file mode 100644 index 0000000000..3c9ed8435e --- /dev/null +++ b/tests/unittests/tests-cpp_ctors/tests-cpp_ctors.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016-2017 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file + * @brief Unittests for C++ constructors + * + * @author Joakim NohlgÄrd + */ +#ifndef TESTS_CPP_CTORS_H +#define TESTS_CPP_CTORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_cpp(void); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +namespace RIOTTestCPP { + /** + * @brief Simple class used for testing constructor calls + */ + class MyClass { + private: + volatile long var; + + public: + MyClass(); + + explicit MyClass(long value); + + long value(); + + void inc(); + }; +} +#endif + +#endif /* TESTS_CPP_CTORS_H */ +/** @} */