diff --git a/docs/dev/mpt_req.md b/docs/dev/mpt_req.md new file mode 100644 index 0000000..bcd2a90 --- /dev/null +++ b/docs/dev/mpt_req.md @@ -0,0 +1,86 @@ +# Eclipse Cyclone DDS Multi Process Testing Requirements + +This document present some requirements and considerations regarding the +[Multi Process Test Framework](multi_process_testing.md). + +## Requirements +1.1) To test certain Cyclone DDS features, multiple processes running Cyclone + DDS are needed to force communication through the whole stack. + +1.2) Should be buildable and runnable on platforms that support multiprocess + and filesystems including the ones used in the continues integration + context. + +1.3) Results should be easily analyzable within the continues integration + context and when running locally. This can be done by reporting the + results in a standard format like xunit or cunit. + +1.4) No processes must be left behind (f.i. deadlock in child process) when the + test finished (or timed out). + +1.5) When running tests parallel, they should not interfere with each other. + +1.6) Processes of the same test should be able to communicate (for settings, + syncing, etc). + +1.7) It should be possible to analyze output/messages/tracing of the parent + and child processes to be able to draw a proper test conclusion. + + +## Considerations +2.1) +The files that actually contain the tests, should be focused on those tests. +This means that the process management and setting up (and usage of) IPC +between test processes should be handled by a test framework so that the +test files can remain as clean as possible. + +2.2) +If possible, there shouldn't be a need for writing log files to a file system +when running the tests normally. It could be helpful, however, that these log +files are written when debugging related tests. + +2.3) +Preferably, the DDS communication between the processes should not leave +localhost. + + +## Intentions +There doesn't seem to be a 3rd party test framework that addresses our +requirements in a satisfactory manner. + +After some discussions with a few people (different people in different +meetings), it was decided to create our own framework and to go in the +following direction: + +- Process creation/destruction/etc is (re)introduced in the ddsrt.
+ [1.1/1.2] + +- The files that contain the tests, should be easy to understand and focus on + the tests themselves.
+ [2.1] + +- Other files (generated or in the framework) should take care of the + intricacies of starting/monitoring the proper processes with the proper + settings.
+ [1.4/1.6/2.1] + +- To do this, a similar approach of the current CUnit build will be used; + CMake will scan the test files and create runners according to macros within + the test files.
+ [2.1] + +- The tests should be executed by CTest. For now this means that a proper + runner exit code for pass/fail is enough. We would like to add CUnit like + output in the future.
+ [1.2/1.3] + +- The Cyclone DDS API contains the possibility to monitor generated log traces. + This means we won't be needing to monitor actual log files. Just register a + log callback and go from there.
+ [1.7/2.2] + +- The framework should be able to generate unique domain ids and unique topic + names when necessary. That way, tests won't interfere with each other when + running in parallel.
+ [1.5] + diff --git a/docs/dev/multi_process_testing.md b/docs/dev/multi_process_testing.md new file mode 100644 index 0000000..aa33f9d --- /dev/null +++ b/docs/dev/multi_process_testing.md @@ -0,0 +1,86 @@ +# Eclipse Cyclone DDS Multi Process Testing + +Some features and functionalities of Cyclone DDS can only be tested when +there's communication between processes. Examples are durability, security, +etc. To really make sure that these kind of features work, extended tests +with multiple processes are needed. + +This results in a number of [requirements](mpt_req.md). + +There doesn't seem to be a 3rd party test framework that addresses our +requirements in a satisfactory manner. Therefore, it was decided to create +our own Multi Process Testing (MPT) framework. + +This document will provide an overview of the MPT framework. + + +## Overview + +An MPT application is basically divided into two components +1. Tests +2. Runner + +The Tests are created by the developer. They don't need to worry about the +process management. They only have to provide process entry point(s), tests +and test processes that use these entry points. E.g. +```cpp +MPT_ProcessEntry(publisher, MPT_Args(int domain)) +{ + /* Publish a sample on the given domain. */ + MPT_ASSERT(success, "publisher failed"); +} +MPT_ProcessEntry(subscriber, MPT_Args(int domain)) +{ + /* Subscribe to a sample from the given domain. */ + MPT_ASSERT(success, "subscriber failed"); +} + +MPT_TestProcess(helloworld, domain0, pub, publisher, MPT_ArgValues(0)); +MPT_TestProcess(helloworld, domain0, sub, subscriber, MPT_ArgValues(0)); +MPT_Test(helloworld, domain0); + +MPT_TestProcess(helloworld, domain42, pub, publisher, MPT_ArgValues(42)); +MPT_TestProcess(helloworld, domain42, sub, subscriber, MPT_ArgValues(42)); +MPT_Test(helloworld, domain42); +``` + +There are more options, but see the +[usage test](../../src/mpt/tests/self/usage.c) for more elaborate examples. + +CMake will identify suites, tests and processes depending on those MPT +macros.
+It'll use that to generate part of the MPT Runner. The Runner takes care +of starting test(s) and handling the process management. + +The runner also takes care of preparing IPC between test processes so that +these processes can sync if they need to (NB, this will be a future extension). + + +#### Suite-Test-Process tree + +A process is related to a test and that test is related to a suite.
+A suite can have multiple tests and tests can have multiple processes.
+ +This results in the following tree quite naturally. + +Suite-Test-Process tree + + +#### Test execution + +There are 3 main ways to start an MPT application. +1. Without argument.
+ All tests will be run. +2. With suite and/or test name patterns as arguments.
+ A subset of tests will be run depending on the provided patterns.
+ This allows ctest to execute single tests. +3. With a specific suite/test/process combination as arguments.
+ An user will normally not use this. + +The third option is used by the MPT application itself to start a specific +test related process. It does so by restarting itself with the proper +suite/test/process combination as indicated by the test. This results +in the following flow. + +MPT application flow + diff --git a/docs/dev/pictures/mpt_flow.png b/docs/dev/pictures/mpt_flow.png new file mode 100644 index 0000000..271e74b Binary files /dev/null and b/docs/dev/pictures/mpt_flow.png differ diff --git a/docs/dev/pictures/mpt_tree.png b/docs/dev/pictures/mpt_tree.png new file mode 100644 index 0000000..eef7644 Binary files /dev/null and b/docs/dev/pictures/mpt_tree.png differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc63136..e56d494 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -186,5 +186,11 @@ endif() add_subdirectory(examples) +if (BUILD_TESTING) + # Multi Process Tests + add_subdirectory(mpt) +endif() + + # Pull-in CPack and support for generating Config.cmake and packages. include(Packaging) diff --git a/src/ddsrt/include/dds/ddsrt/log.h b/src/ddsrt/include/dds/ddsrt/log.h index 4a08a46..360f9c6 100644 --- a/src/ddsrt/include/dds/ddsrt/log.h +++ b/src/ddsrt/include/dds/ddsrt/log.h @@ -107,7 +107,7 @@ typedef struct { /** Function signature that log and trace callbacks must adhere too. */ typedef void(*dds_log_write_fn_t)(void *, const dds_log_data_t *); -extern uint32_t *const dds_log_mask; +DDS_EXPORT extern uint32_t *const dds_log_mask; /** * @brief Get currently enabled log and trace categories. diff --git a/src/mpt/CMakeLists.txt b/src/mpt/CMakeLists.txt new file mode 100644 index 0000000..4b759c7 --- /dev/null +++ b/src/mpt/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.7) + +option(MPT_ENABLE_SELFTEST "Enable multi-process test-framework self test" OFF) + +set(MPT_CMAKE "${CMAKE_CURRENT_SOURCE_DIR}/mpt/cmake/MPT.cmake") +set(MPT_SOURCE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(MPT_BINARY_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +add_subdirectory(mpt) +add_subdirectory(tests) + diff --git a/src/mpt/mpt/CMakeLists.txt b/src/mpt/mpt/CMakeLists.txt new file mode 100644 index 0000000..a81fbe5 --- /dev/null +++ b/src/mpt/mpt/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# + + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/include/mpt/resource.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/mpt/resource.h" @ONLY) + + diff --git a/src/mpt/mpt/cmake/MPT.cmake b/src/mpt/mpt/cmake/MPT.cmake new file mode 100644 index 0000000..fd50b5b --- /dev/null +++ b/src/mpt/mpt/cmake/MPT.cmake @@ -0,0 +1,184 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +set(MPT_DIR "${CMAKE_CURRENT_LIST_DIR}/..") + + + +function(parse_mpt_fixtures INPUT TEST_DISABLED TEST_TIMEOUT TEST_XFAIL) + set(s "[ \t\r\n]") + if(INPUT MATCHES ".disabled${s}*=${s}*([tT][rR][uU][eE]|[0-9]+)") + set(${TEST_DISABLED} "TRUE" PARENT_SCOPE) + else() + set(${TEST_DISABLED} "FALSE" PARENT_SCOPE) + endif() + + if(INPUT MATCHES ".timeout${s}*=${s}*([0-9]+)") + set(${TEST_TIMEOUT} "${CMAKE_MATCH_1}" PARENT_SCOPE) + else() + set(${TEST_TIMEOUT} "0" PARENT_SCOPE) + endif() + + if(INPUT MATCHES ".xfail${s}*=${s}*([tT][rR][uU][eE]|[0-9]+)") + set(${TEST_XFAIL} "true" PARENT_SCOPE) + else() + set(${TEST_XFAIL} "false" PARENT_SCOPE) + endif() +endfunction() + + + +function(process_mpt_source_file SOURCE_FILE SUITES TESTS PROCESSES) + unset(tests) + unset(processes) + set(x "\\*") + set(s "[ \t\r\n]") + set(s_or_x "[ \t\r\n\\*]") + set(w "[_a-zA-Z0-9]") + set(ident_expr "(${s}*${w}+${s}*)") + # Very basic type recognition, only things that contain word characters and + # pointers are handled. And since this script does not actually have to + # compile any code, type checking is left to the compiler. An error (or + # warning) will be thrown if something is off. + # + # The "type" regular expression below will match things like: + # - + # - * + # - * * + set(type_expr "(${s}*${w}+${x}*${s}+${s_or_x}*)+") + set(param_expr "${type_expr}${ident_expr}") + # Test fixture support (based on test fixtures as implemented in Criterion), + # to enable per-test (de)initializers, which is very different from + # per-suite (de)initializers, and timeouts. + # + # The following fixtures are supported: + # - init + # - fini + # - disabled + # - timeout + set(data_expr "(${s}*,${s}*\\.${w}+${s}*=[^,\\)]+)*") + + file(READ "${SOURCE_FILE}" content) + + # MPT_Test + set(test_expr "MPT_Test${s}*\\(${ident_expr},${ident_expr}${data_expr}\\)") + string(REGEX MATCHALL "${test_expr}" matches "${content}") + foreach(match ${matches}) + string(REGEX REPLACE "${test_expr}" "\\1" suite "${match}") + string(REGEX REPLACE "${test_expr}" "\\2" test "${match}") + # Remove leading and trailing whitespace + string(STRIP "${suite}" suite) + string(STRIP "${test}" test) + + # Extract fixtures that must be handled by CMake (.disabled and .timeout). + parse_mpt_fixtures("${match}" disabled timeout xfail) + list(APPEND tests "${suite}:${test}:${disabled}:${timeout}:${xfail}") + list(APPEND suites "${suite}") + endforeach() + + # MPT_TestProcess + set(process_expr "MPT_TestProcess${s}*\\(${ident_expr},${ident_expr},${ident_expr}") + string(REGEX MATCHALL "${process_expr}" matches "${content}") + foreach(match ${matches}) + string(REGEX REPLACE "${process_expr}" "\\1" suite "${match}") + string(REGEX REPLACE "${process_expr}" "\\2" test "${match}") + string(REGEX REPLACE "${process_expr}" "\\3" id "${match}") + # Remove leading and trailing whitespace + string(STRIP "${suite}" suite) + string(STRIP "${test}" test) + string(STRIP "${id}" id) + + list(APPEND processes "${suite}:${test}:${id}") + endforeach() + + set(${PROCESSES} ${processes} PARENT_SCOPE) + set(${TESTS} ${tests} PARENT_SCOPE) + set(${SUITES} ${suites} PARENT_SCOPE) +endfunction() + + + +function(add_mpt_executable TARGET) + set(sources) + set(processes) + + foreach(source ${ARGN}) + if((EXISTS "${source}" OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source}")) + unset(processes) + unset(tests) + unset(suites) + + # Disable missing-field-initializers warnings as not having to specify + # every member, aka fixture, is intended behavior. + if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR + ${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang" OR + ${CMAKE_C_COMPILER_ID} STREQUAL "GNU") + set_property( + SOURCE "${source}" + PROPERTY COMPILE_FLAGS -Wno-missing-field-initializers) + endif() + + process_mpt_source_file("${source}" suites tests processes) + + foreach(suite ${suites}) + set(addsuites "${addsuites}\n mpt_add_suite(mpt_suite_new(\"${suite}\"));") + endforeach() + + foreach(testcase ${tests}) + string(REPLACE ":" ";" testcase ${testcase}) + list(GET testcase 0 suite) + list(GET testcase 1 test) + list(GET testcase 2 disabled) + list(GET testcase 3 timeout) + list(GET testcase 4 xfail) + set(addtests "${addtests}\n mpt_add_test(\"${suite}\", mpt_test_new(\"${test}\", ${timeout}, ${xfail}));") + + # Add this test to ctest. + set(ctest "${TARGET}_${suite}_${test}") + add_test( + NAME ${ctest} + COMMAND ${TARGET} -s ${suite} -t ${test}) + set_property(TEST ${ctest} PROPERTY TIMEOUT ${timeout}) + set_property(TEST ${ctest} PROPERTY DISABLED ${disabled}) + endforeach() + + foreach(process ${processes}) + string(REPLACE ":" ";" process ${process}) + list(GET process 0 suite) + list(GET process 1 test) + list(GET process 2 id) + set(addprocs "${addprocs}\n mpt_add_process(\"${suite}\", \"${test}\", mpt_process_new(\"${id}\", MPT_TestProcessName(${suite}, ${test}, ${id})));") + set(procdecls "${procdecls}\nextern MPT_TestProcessDeclaration(${suite}, ${test}, ${id});") + endforeach() + + list(APPEND sources "${source}") + endif() + endforeach() + + configure_file( + "${MPT_DIR}/src/main.c.in" "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.c" @ONLY) + + add_executable( + ${TARGET} "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.c" ${sources}) + + target_include_directories(${TARGET} PRIVATE "${MPT_DIR}/include" "${MPT_BINARY_ROOT_DIR}/mpt/include") + target_link_libraries(${TARGET} PRIVATE ddsc) + + # We need the 'expand environment variables' feature that is present in the + # 'util' module. However, it is currently not possible to properly link to + # that module on Windows. In the near future, the utils will be migrated to + # ddsrt, after which we automatically have access to expand_envvars. + # But until then, use this very ugly (but quick) hack to solve our immediate + # build issues. + target_include_directories(${TARGET} PRIVATE "${CMAKE_SOURCE_DIR}/util/include") + target_sources(${TARGET} PRIVATE "${CMAKE_SOURCE_DIR}/util/src/ut_expand_envvars.c") +endfunction() + diff --git a/src/mpt/mpt/include/mpt/mpt.h b/src/mpt/mpt/include/mpt/mpt.h new file mode 100644 index 0000000..8d0522a --- /dev/null +++ b/src/mpt/mpt/include/mpt/mpt.h @@ -0,0 +1,158 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef MPT_H_INCLUDED +#define MPT_H_INCLUDED + +#include +#include +#include "mpt/resource.h" +#include "mpt/private/mpt.h" +#include "dds/ddsrt/environ.h" + + +/* Environment name/value pair. */ +typedef struct mpt_env_ { + const char *name; + const char *value; +} mpt_env_t; + + +/* Process entry argument definitions. */ +#define MPT_Args(...) MPT_ProcessArgsSyntax, __VA_ARGS__ +#define MPT_NoArgs() MPT_ProcessArgsSyntax + +#define MPT_ArgValues(...) MPT_ProcessArgs, __VA_ARGS__ +#define MPT_NoArgValues() MPT_ProcessArgs + + +/* Process entry definition. */ +#define MPT_ProcessEntry(process, args)\ +void MPT_ProcessEntryName(process)(args) + + +/* IPC functions. */ +#define MPT_Send(str) mpt_ipc_send(MPT_ProcessArgs, str); +#define MPT_Wait(str) mpt_ipc_wait(MPT_ProcessArgs, str); + + +/* + * MPT_TestProcess generates a wrapper function that takes care of + * per-process initialization, environment settings, + * deinitialization and the actual process entry call. + */ +#define MPT_TestProcess(suite, test, name, process, args, ...) \ +MPT_TestInitDeclaration(suite, test); \ +MPT_TestFiniDeclaration(suite, test); \ +MPT_TestProcessDeclaration(suite, test, name) \ +{ \ + mpt_data_t data = MPT_Fixture(__VA_ARGS__); \ + \ + /* Always export the process name. */ \ + /* This can be used to generate unique log files fi. */ \ + ddsrt_setenv("MPT_PROCESS_NAME", \ + MPT_XSTR(MPT_TestProcessName(suite, test, name))); \ + \ + /* Initialize test related stuff first. */ \ + MPT_TestInitName(suite, test)(); \ + \ + /* Pre-process initialization. */ \ + mpt_export_env(data.environment); \ + if (data.init != NULL) { \ + data.init(); \ + } \ + \ + /* Execute the actual process entry function. */ \ + MPT_ProcessEntryName(process)(args); \ + \ + /* Teardown process and test. */ \ + if (data.fini != NULL) { \ + data.fini(); \ + } \ + MPT_TestFiniName(suite, test)(); \ +} + + +/* + * MPT_Test generates wrapper functions that take care of + * per-test initialization, environment settings and + * deinitialization. + * This is also used by CMake to determine the ctest timeout + * and disabled settings. + */ +#define MPT_Test(suite, test, ...) \ +MPT_TestInitDeclaration(suite, test) \ +{ \ + mpt_data_t data = MPT_Fixture(__VA_ARGS__); \ + mpt_export_env(data.environment); \ + if (data.init != NULL) { \ + data.init(); \ + } \ +} \ +MPT_TestFiniDeclaration(suite, test) \ +{ \ + mpt_data_t data = MPT_Fixture(__VA_ARGS__); \ + if (data.fini != NULL) { \ + data.fini(); \ + } \ +} + + +/* + * Test asserts. + * Printing is supported eg MPT_ASSERT_EQ(a, b, "foo: %s", bar") + */ +#define MPT_ASSERT(cond, ...) MPT__ASSERT__(cond, MPT_FATAL_NO, __VA_ARGS__) + +#define MPT_ASSERT_FAIL(...) MPT_ASSERT(0, __VA_ARGS__) + +#define MPT_ASSERT_EQ(value, expected, ...) MPT_ASSERT((value == expected), __VA_ARGS__) +#define MPT_ASSERT_NEQ(value, expected, ...) MPT_ASSERT((value != expected), __VA_ARGS__) +#define MPT_ASSERT_LEQ(value, expected, ...) MPT_ASSERT((value <= expected), __VA_ARGS__) +#define MPT_ASSERT_GEQ(value, expected, ...) MPT_ASSERT((value >= expected), __VA_ARGS__) +#define MPT_ASSERT_LT(value, expected, ...) MPT_ASSERT((value < expected), __VA_ARGS__) +#define MPT_ASSERT_GT(value, expected, ...) MPT_ASSERT((value > expected), __VA_ARGS__) + +#define MPT_ASSERT_NULL(value, ...) MPT_ASSERT((value == NULL), __VA_ARGS__) +#define MPT_ASSERT_NOT_NULL(value, ...) MPT_ASSERT((value != NULL), __VA_ARGS__) + +#define MPT_ASSERT_STR_EQ(value, expected, ...) MPT_ASSERT((MPT_STRCMP(value, expected, 1) == 0), __VA_ARGS__) +#define MPT_ASSERT_STR_NEQ(value, expected, ...) MPT_ASSERT((MPT_STRCMP(value, expected, 0) != 0), __VA_ARGS__) +#define MPT_ASSERT_STR_EMPTY(value, ...) MPT_ASSERT((MPT_STRLEN(value, 1) == 0), __VA_ARGS__) +#define MPT_ASSERT_STR_NOT_EMPTY(value, ...) MPT_ASSERT((MPT_STRLEN(value, 0) > 0), __VA_ARGS__) + + +/* Fatal just means that control is returned to the parent function. */ +#define MPT_ASSERT_FATAL(cond, ...) MPT__ASSERT__(cond, MPT_FATAL_YES, __VA_ARGS__) + +#define MPT_ASSERT_FATAL_FAIL(...) MPT_ASSERT_FATAL(0, __VA_ARGS__) + +#define MPT_ASSERT_FATAL_EQ(value, expected, ...) MPT_ASSERT_FATAL((value == expected), __VA_ARGS__) +#define MPT_ASSERT_FATAL_NEQ(value, expected, ...) MPT_ASSERT_FATAL((value != expected), __VA_ARGS__) +#define MPT_ASSERT_FATAL_LEQ(value, expected, ...) MPT_ASSERT_FATAL((value <= expected), __VA_ARGS__) +#define MPT_ASSERT_FATAL_GEQ(value, expected, ...) MPT_ASSERT_FATAL((value >= expected), __VA_ARGS__) +#define MPT_ASSERT_FATAL_LT(value, expected, ...) MPT_ASSERT_FATAL((value < expected), __VA_ARGS__) +#define MPT_ASSERT_FATAL_GT(value, expected, ...) MPT_ASSERT_FATAL((value > expected), __VA_ARGS__) + +#define MPT_ASSERT_FATAL_NULL(value, ...) MPT_ASSERT_FATAL((value == NULL), __VA_ARGS__) +#define MPT_ASSERT_FATAL_NOT_NULL(value, ...) MPT_ASSERT_FATAL((value != NULL), __VA_ARGS__) + +#define MPT_ASSERT_FATAL_STR_EQ(value, expected, ...) MPT_ASSERT_FATAL((MPT_STRCMP(value, expected, 1) == 0), __VA_ARGS__) +#define MPT_ASSERT_FATAL_STR_NEQ(value, expected, ...) MPT_ASSERT_FATAL((MPT_STRCMP(value, expected, 0) != 0), __VA_ARGS__) +#define MPT_ASSERT_FATAL_STR_EMPTY(value, ...) MPT_ASSERT_FATAL((MPT_STRLEN(value, 1) == 0), __VA_ARGS__) +#define MPT_ASSERT_FATAL_STR_NOT_EMPTY(value, ...) MPT_ASSERT_FATAL((MPT_STRLEN(value, 0) > 0), __VA_ARGS__) + + +/* Helpful function to check for patterns in log callbacks. */ +int mpt_patmatch(const char *pat, const char *str); + + +#endif /* MPT_H_INCLUDED */ diff --git a/src/mpt/mpt/include/mpt/private/mpt.h b/src/mpt/mpt/include/mpt/private/mpt.h new file mode 100644 index 0000000..e167e1d --- /dev/null +++ b/src/mpt/mpt/include/mpt/private/mpt.h @@ -0,0 +1,153 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef MPT_PRIVATE_H_INCLUDED +#define MPT_PRIVATE_H_INCLUDED + +#include +#include + + +/* + * Just some helpful macros. + */ +#define MPT_XSTR(s) MPT_STR(s) +#define MPT_STR(s) #s + +#define MPT_STRCMP(value, expected, err) \ + (((value != NULL) && (expected != NULL)) ? strcmp(value, expected) : err) + +#define MPT_STRLEN(value, err) \ + ((value != NULL) ? strlen(value) : err) + +#define MPT_ProcessArgs mpt__args__, mpt__retval__ +#define MPT_ProcessArgsSyntax \ + const mpt_data_t *mpt__args__, mpt_retval_t *mpt__retval__ + + + +/* + * Name and declaration macros. + */ +#define MPT_ProcessEntryName(process) \ + MPT_ProcessEntry__ ## process + +#define MPT_TestInitName(suite, test) \ + MPT_TestInit__##suite##_##test + +#define MPT_TestInitDeclaration(suite, test) \ +void MPT_TestInitName(suite, test)(void) + +#define MPT_TestFiniName(suite, test) \ + MPT_TestFini__##suite##_##test + +#define MPT_TestFiniDeclaration(suite, test) \ +void MPT_TestFiniName(suite, test)(void) + +#define MPT_TestProcessName(suite, test, name) \ + MPT_TestProcess__##suite##_##test##_##name + +#define MPT_TestProcessDeclaration(suite, test, name) \ +void MPT_TestProcessName(suite, test, name) (MPT_ProcessArgsSyntax) + + + +/* + * MPT Assert impl. + */ +typedef enum { + MPT_SUCCESS = 0, + MPT_FAILURE +} mpt_retval_t; + +#define MPT_FATAL_YES 1 +#define MPT_FATAL_NO 0 + +#ifdef _WIN32 +/* Microsoft Visual Studio does not expand __VA_ARGS__ correctly. */ +#define MPT__ASSERT__(...) MPT__ASSERT____((__VA_ARGS__)) +#define MPT__ASSERT____(tuple) MPT__ASSERT___ tuple +#else +#define MPT__ASSERT__(...) MPT__ASSERT___(__VA_ARGS__) +#endif /* _WIN32 */ + +#define MPT__ASSERT___(cond, fatal, ...) \ + do { \ + (void)mpt__args__; /* Satisfy compiler. */ \ + if (!(cond)) { \ + if (*mpt__retval__ == MPT_SUCCESS) { \ + *mpt__retval__ = MPT_FAILURE; \ + } \ + printf("MPT_FAIL(%s, %d):\n", __FILE__, __LINE__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + if (fatal == MPT_FATAL_YES) { \ + return; \ + } \ + } \ + } while(0) + + + +/* + * MPT Fixture impl. + */ +struct mpt_env_; + +typedef void(*mpt_init_func_t)(void); +typedef void(*mpt_fini_func_t)(void); + +typedef struct { + /* Test and process fixtures. */ + mpt_init_func_t init; + mpt_fini_func_t fini; + struct mpt_env_ *environment; + /* Test fixtures. */ + bool disabled; + int timeout; + bool xfail; + /* IPC information. */ + int todo; +} mpt_data_t; + +/* Microsoft Visual Studio does not like empty struct initializers, i.e. + no fixtures are specified. To work around that issue MPT_Fixture inserts a + NULL initializer as fall back. */ +#define MPT_Comma() , +#define MPT_Reduce(one, ...) one + +#ifdef _WIN32 +/* Microsoft Visual Studio does not expand __VA_ARGS__ correctly. */ +#define MPT_Fixture__(...) MPT_Fixture____((__VA_ARGS__)) +#define MPT_Fixture____(tuple) MPT_Fixture___ tuple +#else +#define MPT_Fixture__(...) MPT_Fixture___(__VA_ARGS__) +#endif /* _WIN32 */ + +#define MPT_Fixture___(throw, away, value, ...) value + +#define MPT_Fixture_(throwaway, ...) \ + MPT_Fixture__(throwaway, ((mpt_data_t){ 0 }), ((mpt_data_t){ __VA_ARGS__ })) + +#define MPT_Fixture(...) \ + MPT_Fixture_( MPT_Comma MPT_Reduce(__VA_ARGS__,) (), __VA_ARGS__ ) + + + +/* + * MPT Support functions. + */ +void mpt_export_env(const struct mpt_env_ *env); +void mpt_ipc_send(MPT_ProcessArgsSyntax, const char *str); +void mpt_ipc_wait(MPT_ProcessArgsSyntax, const char *str); + + +#endif /* MPT_PRIVATE_H_INCLUDED */ diff --git a/src/mpt/mpt/include/mpt/resource.h.in b/src/mpt/mpt/include/mpt/resource.h.in new file mode 100644 index 0000000..13c5711 --- /dev/null +++ b/src/mpt/mpt/include/mpt/resource.h.in @@ -0,0 +1,6 @@ +#ifndef MPT_RESOURCE_H_INCLUDED +#define MPT_RESOURCE_H_INCLUDED + +#define MPT_SOURCE_ROOT_DIR "@MPT_SOURCE_ROOT_DIR@" + +#endif /* MPT_RESOURCE_H_INCLUDED */ diff --git a/src/mpt/mpt/src/main.c.in b/src/mpt/mpt/src/main.c.in new file mode 100644 index 0000000..31f0689 --- /dev/null +++ b/src/mpt/mpt/src/main.c.in @@ -0,0 +1,551 @@ +#include +#include +#include +#include +#include "mpt/mpt.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/environ.h" +#include "dds/util/ut_expand_envvars.h" + +#ifndef _WIN32 +#include +#else +#define EX_USAGE (64) +#define EX_SOFTWARE (70) +#endif /* _WIN32 */ + + + +/************************************************ + * Support functions. + ************************************************/ +int +mpt_patmatch(const char *pat, const char *str) +{ + while (*pat) { + if (*pat == '?') { + /* any character will do */ + if (*str++ == 0) { + return 0; + } + pat++; + } else if (*pat == '*') { + /* collapse a sequence of wildcards, requiring as many + characters in str as there are ?s in the sequence */ + while (*pat == '*' || *pat == '?') { + if (*pat == '?' && *str++ == 0) { + return 0; + } + pat++; + } + /* try matching on all positions where str matches pat */ + while (*str) { + if (*str == *pat && mpt_patmatch(pat+1, str+1)) { + return 1; + } + str++; + } + return *pat == 0; + } else { + /* only an exact match */ + if (*str++ != *pat++) { + return 0; + } + } + } + + return *str == 0; +} + +void +mpt_export_env(const mpt_env_t *env) +{ + if (env) { + while ((env->name != NULL) && (env->value != NULL)) { + char *expanded = ut_expand_envvars(env->value); + ddsrt_setenv(env->name, expanded); + ddsrt_free(expanded); + env++; + } + } +} + +void +mpt_ipc_send(MPT_ProcessArgsSyntax, const char *str) +{ + (void)str; + (void)mpt__args__; + /* TODO: implement. */ + MPT_ASSERT(0, "mpt_ipc_send not implemented"); +} + +void +mpt_ipc_wait(MPT_ProcessArgsSyntax, const char *str) +{ + (void)str; + (void)mpt__args__; + /* TODO: implement. */ + MPT_ASSERT(0, "mpt_ipc_wait not implemented"); +} + + + +/************************************************ + * Processes. + ************************************************/ +@procdecls@ + +typedef void(*mpt_func_proc_t)( + const mpt_data_t *mpt__args__, mpt_retval_t *mpt__retval__); + +typedef struct mpt_process_ { + const char* name; + ddsrt_pid_t pid; + mpt_func_proc_t process; + struct mpt_process_ *next; +} mpt_process_t; + +static mpt_process_t* +mpt_process_new(const char* name, mpt_func_proc_t process) +{ + mpt_process_t *proc; + proc = ddsrt_malloc(sizeof(mpt_process_t)); + proc->pid = 0; + proc->name = name; + proc->process = process; + proc->next = NULL; + return proc; +} + +static void +mpt_process_freelist(mpt_process_t *proc) +{ + if (proc) { + mpt_process_freelist(proc->next); + if (proc->pid != 0) { + printf("Process %s kill(%d)\n", proc->name, (int)proc->pid); + ddsrt_proc_kill(proc->pid); + } + ddsrt_free(proc); + } +} + + + +/************************************************ + * Tests. + ************************************************/ +typedef struct mpt_test_ { + const char* name; + bool xfail; + dds_duration_t timeout; + mpt_process_t *procs; + struct mpt_test_ *next; +} mpt_test_t; + +static mpt_test_t* +mpt_test_new(const char* name, int secs, bool xf) +{ + mpt_test_t *test; + test = ddsrt_malloc(sizeof(mpt_test_t)); + test->procs = NULL; + test->name = name; + test->xfail = xf; + + /* This test will stop after a given timeout. However, when running in + * ctest, we'd like to use the ctest provided timeout functionality. + * So, make sure that the 'manual' timeout takes longer than the ctest + * timeout. */ + if (secs == 0) { + test->timeout = DDS_SECS(1600); + } else { + test->timeout = DDS_SECS(secs * 2); + } + + return test; +} + +static void +mpt_test_freelist(mpt_test_t *test) +{ + if (test) { + mpt_process_freelist(test->procs); + mpt_test_freelist(test->next); + } + ddsrt_free(test); +} + +static void +mpt_test_add_process(mpt_test_t *test, mpt_process_t *proc) +{ + /* Prepend */ + proc->next = test->procs; + test->procs = proc; +} + + + +/************************************************ + * Suites. + ************************************************/ +typedef struct mpt_suite_ { + const char* name; + mpt_test_t *tests; + struct mpt_suite_ *next; +} mpt_suite_t; + +static mpt_suite_t* +mpt_suite_new(const char* name) +{ + mpt_suite_t *suite; + suite = ddsrt_malloc(sizeof(mpt_suite_t)); + suite->tests = NULL; + suite->name = name; + return suite; +} + +static void +mpt_suite_freelist(mpt_suite_t *suite) +{ + if (suite) { + mpt_test_freelist(suite->tests); + mpt_suite_freelist(suite->next); + } + ddsrt_free(suite); +} + +static void +mpt_suite_add_test(mpt_suite_t *suite, mpt_test_t *test) +{ + /* Prepend */ + test->next = suite->tests; + suite->tests = test; +} + +static mpt_test_t* +mpt_suite_find_test( + mpt_suite_t *suite, const char *tname) +{ + mpt_test_t *found = suite->tests; + while (found) { + if (mpt_patmatch(tname, found->name)) { + break; + } + found = found->next; + } + return found; +} + + + +/************************************************ + * Root. + ************************************************/ +mpt_suite_t *root = NULL; + +static void +mpt_add_suite(mpt_suite_t *suite) +{ + /* Prepend */ + suite->next = root; + root = suite; +} + +static mpt_suite_t* +mpt_find_suite(const char *sname) +{ + mpt_suite_t *found = root; + while (found) { + if (mpt_patmatch(sname, found->name)) { + break; + } + found = found->next; + } + return found; +} + +static void +mpt_add_test(const char *sname, mpt_test_t *test) +{ + mpt_suite_t *suite = mpt_find_suite(sname); + assert(suite); + mpt_suite_add_test(suite, test); +} + +static void +mpt_add_process(const char *sname, const char *tname, mpt_process_t *proc) +{ + mpt_suite_t *suite = mpt_find_suite(sname); + mpt_test_t *test = mpt_suite_find_test(suite, tname); + assert(suite); + assert(test); + mpt_test_add_process(test, proc); +} + +static void +mpt_free(void) +{ + mpt_suite_freelist(root); + root = NULL; +} + + + +/************************************************ + * Runner. + ************************************************/ +static int +mpt_run_test(const char *exe, mpt_suite_t *suite, mpt_test_t *test) +{ + int result = EXIT_SUCCESS; + mpt_process_t *proc; + dds_retcode_t retcode; + char *argv[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + argv[0] = "-s"; + argv[1] = (char*)suite->name; + argv[2] = "-t"; + argv[3] = (char*)test->name; + + /* Start the processes. */ + proc = test->procs; + while ((proc) && (result == EXIT_SUCCESS)) { + if (proc == test->procs) { + printf("\n\n"); + printf("=====================================================\n"); + printf("Suite: %s\n", suite->name); + printf("Test: %s\n", test->name); + printf("=====================================================\n"); + } + argv[4] = "-p"; + argv[5] = (char*)proc->name; + retcode = ddsrt_proc_create(exe, argv, &proc->pid); + if (retcode != DDS_RETCODE_OK) { + printf("Start %s::%s::%s failed\n", suite->name, test->name, proc->name); + proc->pid = 0; + result = EXIT_FAILURE; + } + proc = proc->next; + } + + /* Wait for the processes. */ + retcode = DDS_RETCODE_OK; + while ((result == EXIT_SUCCESS) && (retcode == DDS_RETCODE_OK)) { + int32_t status; + ddsrt_pid_t pid; + /* A second/third/etc wait will restart the timeout. + * This means that the end timeout can take longer than the requested + * test timeout. However, that's good enough for our purpose. */ + retcode = ddsrt_proc_waitpids(test->timeout, &pid, &status); + if (retcode == DDS_RETCODE_OK) { + proc = test->procs; + while (proc) { + if (proc->pid == pid) { + break; + } + proc = proc->next; + } + if (proc) { + proc->pid = 0; + if (status != 0) { + printf("Process %s::%s::%s failed (%d)\n", suite->name, test->name, proc->name, status); + result = EXIT_FAILURE; + } + } else { + printf("Wait for processes of %s::%s return unknown pid %d\n", suite->name, test->name, (int)pid); + result = EXIT_FAILURE; + } + } else if (retcode != DDS_RETCODE_NOT_FOUND) { + printf("Wait for processes of %s::%s failed (%d)\n", suite->name, test->name, (int)retcode); + result = EXIT_FAILURE; + } + } + + /* Be sure to kill all remaining processes when needed. */ + if (result != EXIT_SUCCESS) { + proc = test->procs; + while (proc) { + if (proc->pid != 0) { + printf("Process %s::%s::%s kill(%d)\n", suite->name, test->name, proc->name, (int)proc->pid); + ddsrt_proc_kill(proc->pid); + ddsrt_proc_waitpid(proc->pid, DDS_SECS(10), NULL); + proc->pid = 0; + } + proc = proc->next; + } + } + + /* Revert result when we expect the test to have failed. */ + if (test->xfail) { + result = ((result == EXIT_SUCCESS) ? EXIT_FAILURE : EXIT_SUCCESS); + } + + return result; +} + +static int +mpt_run_tests(const char *exe, const char *spattern, const char *tpattern) +{ + int result = EXIT_SUCCESS; + mpt_suite_t *suite = root; + while (suite) { + if (mpt_patmatch(spattern, suite->name)) { + mpt_test_t *test = suite->tests; + while (test) { + if (mpt_patmatch(tpattern, test->name)) { + int run = mpt_run_test(exe, suite, test); + if (run != EXIT_SUCCESS) { + result = run; + } + } + test = test->next; + } + } + suite = suite->next; + } + return result; +} + +static int +mpt_run_proc(mpt_process_t *proc) +{ + mpt_retval_t retval = MPT_SUCCESS; + mpt_data_t args; + proc->process(&args, &retval); + return (retval == MPT_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static int +mpt_run_procs(const char *spattern, const char *tpattern, const char *ppattern) +{ + int result = EXIT_SUCCESS; + mpt_suite_t *suite = root; + while (suite) { + if (mpt_patmatch(spattern, suite->name)) { + mpt_test_t *test = suite->tests; + while (test) { + if (mpt_patmatch(tpattern, test->name)) { + mpt_process_t *proc = test->procs; + while (proc) { + if (mpt_patmatch(ppattern, proc->name)) { + int run = mpt_run_proc(proc); + if (run != EXIT_SUCCESS) { + result = run; + } + } + proc = proc->next; + } + } + test = test->next; + } + } + suite = suite->next; + } + return result; +} + + + +/************************************************ + * Main functionality. + ************************************************/ +static struct { + bool print_help; + const char *suite; + const char *test; + const char *process; +} opts = { + false, + "*", + "*", + NULL +}; + +static int parse_options(int argc, char *argv[]) +{ + int err = 0; + + for (int i = 1; err == 0 && i < argc; i++) { + switch ((argv[i][0] == '-') ? argv[i][1] : 0) { + case 'h': + opts.print_help = true; + break; + case 's': + if ((i+1) < argc) { + opts.suite = argv[++i]; + break; + } + /* FALLS THROUGH */ + case 't': + if ((i+1) < argc) { + opts.test = argv[++i]; + break; + } + /* FALLS THROUGH */ + case 'p': + if ((i+1) < argc) { + opts.process = argv[++i]; + break; + } + /* FALLS THROUGH */ + default: + err = 1; + break; + } + } + + return err; +} + +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s OPTIONS\n", name); + fprintf(stderr, "Try '%s -h' for more information\n", name); +} + +static void help(const char *name) +{ + printf("Usage: %s [OPTIONS]\n", name); + printf("\n"); + printf("Possible options:\n"); + printf(" -h display this help and exit\n"); + printf(" -s PATTERN run only tests in suites matching pattern\n"); + printf(" -t PATTERN run only test matching pattern\n"); + printf(" -p PROCESS run only process matching pattern\n"); + printf("\n"); + printf("Exit codes:\n"); + printf(" %-2d Successful termination\n", EXIT_SUCCESS); + printf(" %-2d One or more failing test cases\n", EXIT_FAILURE); + printf(" %-2d Command line usage error\n", EX_USAGE); + printf(" %-2d Internal software error\n", EX_SOFTWARE); +} + +int main(int argc, char *argv[]) +{ + int result = EXIT_SUCCESS; + + if (parse_options(argc, argv) != 0) { + usage(argv[0]); + return EX_USAGE; + } else if (opts.print_help) { + help(argv[0]); + return result; + } + + atexit(mpt_free); + @addsuites@ + @addtests@ + @addprocs@ + + if (opts.process == NULL) { + /* Run test(s). */ + result = mpt_run_tests(argv[0], opts.suite, opts.test); + } else { + /* Run process(es). */ + result = mpt_run_procs(opts.suite, opts.test, opts.process); + } + + return result; +} + diff --git a/src/mpt/tests/CMakeLists.txt b/src/mpt/tests/CMakeLists.txt new file mode 100644 index 0000000..91a9183 --- /dev/null +++ b/src/mpt/tests/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.7) + +if(MPT_ENABLE_SELFTEST) + add_subdirectory(self) +endif() + +add_subdirectory(basic) + diff --git a/src/mpt/tests/basic/CMakeLists.txt b/src/mpt/tests/basic/CMakeLists.txt new file mode 100644 index 0000000..cb2efba --- /dev/null +++ b/src/mpt/tests/basic/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include(${MPT_CMAKE}) + +set(sources + "procs/hello.c" + "helloworld.c" + "multi.c") + +add_mpt_executable(mpt_basic ${sources}) + +idlc_generate(mpt_basic_helloworlddata_lib "procs/helloworlddata.idl") +target_link_libraries(mpt_basic PRIVATE mpt_basic_helloworlddata_lib) + diff --git a/src/mpt/tests/basic/etc/config_any.xml b/src/mpt/tests/basic/etc/config_any.xml new file mode 100644 index 0000000..68e0e0a --- /dev/null +++ b/src/mpt/tests/basic/etc/config_any.xml @@ -0,0 +1,30 @@ + + + + any + + + + auto + true + true + + + lax + + + + diff --git a/src/mpt/tests/basic/etc/config_specific.xml b/src/mpt/tests/basic/etc/config_specific.xml new file mode 100644 index 0000000..2ae3286 --- /dev/null +++ b/src/mpt/tests/basic/etc/config_specific.xml @@ -0,0 +1,30 @@ + + + + ${DOMAIN_ID} + + + + auto + true + true + + + lax + + + + diff --git a/src/mpt/tests/basic/helloworld.c b/src/mpt/tests/basic/helloworld.c new file mode 100644 index 0000000..c959edb --- /dev/null +++ b/src/mpt/tests/basic/helloworld.c @@ -0,0 +1,63 @@ +#include "dds/dds.h" +#include "mpt/mpt.h" +#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */ +#include "procs/hello.h" /* publisher and subscriber entry points. */ + + +/* + * Tests to check simple communication between a publisher and subscriber. + * The published text should be received by the subscriber. + */ + + +/* Environments */ +static mpt_env_t environment_any[] = { + { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" }, + { "CYCLONEDDS_URI", "file://${ETC_DIR}/config_any.xml" }, + { NULL, NULL } +}; +static mpt_env_t environment_42[] = { + { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" }, + { "DOMAIN_ID", "42" }, + { "CYCLONEDDS_URI", "file://${ETC_DIR}/config_specific.xml" }, + { NULL, NULL } +}; + + + +/********************************************************************** + * No CYCLONEDDS_URI set. + **********************************************************************/ +#define TEST_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_def", 1, "No environment set") +MPT_TestProcess(helloworld, default, pub, hello_publisher, TEST_ARGS); +MPT_TestProcess(helloworld, default, sub, hello_subscriber, TEST_ARGS); +MPT_Test(helloworld, default, .init=hello_init, .fini=hello_fini); +#undef TEST_ARGS + + + +/********************************************************************** + * Config domain is any. Test domain is default. + **********************************************************************/ +#define TEST_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_any", 1, "Some nice text over any domain") +MPT_TestProcess(helloworld, domain_any, pub, hello_publisher, TEST_ARGS); +MPT_TestProcess(helloworld, domain_any, sub, hello_subscriber, TEST_ARGS); +MPT_Test(helloworld, domain_any, .init=hello_init, .fini=hello_fini, .environment=environment_any); +#undef TEST_ARGS + + + +/********************************************************************** + * Pub: Config domain is any. Test domain is 42. + * Sub: Config domain is 42 (through DOMAIN_ID env). Test domain is default. + **********************************************************************/ +#define TEST_PUB_ARGS MPT_ArgValues(42, "hello_42", 1, "Now domain 42 is used") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_42", 1, "Now domain 42 is used") +MPT_TestProcess(helloworld, domain_42, pub, hello_publisher, TEST_PUB_ARGS, .environment=environment_any); +MPT_TestProcess(helloworld, domain_42, sub, hello_subscriber, TEST_SUB_ARGS, .environment=environment_42); +MPT_Test(helloworld, domain_42, .init=hello_init, .fini=hello_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS + + + diff --git a/src/mpt/tests/basic/multi.c b/src/mpt/tests/basic/multi.c new file mode 100644 index 0000000..4ed5743 --- /dev/null +++ b/src/mpt/tests/basic/multi.c @@ -0,0 +1,50 @@ +#include "mpt/mpt.h" +#include "procs/hello.h" + + +/* + * Tests to check communication between multiple publisher(s) and subscriber(s). + */ + + +/* + * The publisher expects 2 publication matched. + * The subscribers expect 1 sample each. + */ +#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubsubsub", 2, "pubsubsub") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubsubsub", 1, "pubsubsub") +MPT_TestProcess(multi, pubsubsub, pub, hello_publisher, TEST_PUB_ARGS); +MPT_TestProcess(multi, pubsubsub, sub1, hello_subscriber, TEST_SUB_ARGS); +MPT_TestProcess(multi, pubsubsub, sub2, hello_subscriber, TEST_SUB_ARGS); +MPT_Test(multi, pubsubsub, .init=hello_init, .fini=hello_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS + + +/* + * The publishers expect 1 publication matched each. + * The subscriber expects 2 samples. + */ +#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsub", 1, "pubpubsub") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsub", 2, "pubpubsub") +MPT_TestProcess(multi, pubpubsub, pub1, hello_publisher, TEST_PUB_ARGS); +MPT_TestProcess(multi, pubpubsub, pub2, hello_publisher, TEST_PUB_ARGS); +MPT_TestProcess(multi, pubpubsub, sub, hello_subscriber, TEST_SUB_ARGS); +MPT_Test(multi, pubpubsub, .init=hello_init, .fini=hello_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS + + +/* + * The publishers expect 2 publication matched each. + * The subscribers expect 2 samples each. + */ +#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsubsub", 2, "pubpubsubsub") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsubsub", 2, "pubpubsubsub") +MPT_TestProcess(multi, pubpubsubsub, pub1, hello_publisher, TEST_PUB_ARGS); +MPT_TestProcess(multi, pubpubsubsub, pub2, hello_publisher, TEST_PUB_ARGS); +MPT_TestProcess(multi, pubpubsubsub, sub1, hello_subscriber, TEST_SUB_ARGS); +MPT_TestProcess(multi, pubpubsubsub, sub2, hello_subscriber, TEST_SUB_ARGS); +MPT_Test(multi, pubpubsubsub, .init=hello_init, .fini=hello_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS diff --git a/src/mpt/tests/basic/procs/hello.c b/src/mpt/tests/basic/procs/hello.c new file mode 100644 index 0000000..2c68a84 --- /dev/null +++ b/src/mpt/tests/basic/procs/hello.c @@ -0,0 +1,239 @@ +#include +#include +#include + +#include "mpt/mpt.h" + +#include "dds/dds.h" +#include "helloworlddata.h" + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/strtol.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/sync.h" + + +/* An array of one message (aka sample in dds terms) will be used. */ +#define MAX_SAMPLES 1 + +static int g_publication_matched_count = 0; +static ddsrt_mutex_t g_mutex; +static ddsrt_cond_t g_cond; + +static void +publication_matched_cb( + dds_entity_t writer, + const dds_publication_matched_status_t status, + void* arg) +{ + (void)arg; + (void)writer; + ddsrt_mutex_lock(&g_mutex); + g_publication_matched_count = (int)status.current_count; + ddsrt_cond_broadcast(&g_cond); + ddsrt_mutex_unlock(&g_mutex); +} + +static void +data_available_cb( + dds_entity_t reader, + void* arg) +{ + (void)arg; + (void)reader; + ddsrt_mutex_lock(&g_mutex); + ddsrt_cond_broadcast(&g_cond); + ddsrt_mutex_unlock(&g_mutex); +} + +void +hello_init(void) +{ + ddsrt_init(); + ddsrt_mutex_init(&g_mutex); + ddsrt_cond_init(&g_cond); +} + +void +hello_fini(void) +{ + ddsrt_cond_destroy(&g_cond); + ddsrt_mutex_destroy(&g_mutex); + ddsrt_fini(); +} + + +/* + * The HelloWorld publisher. + * It waits for a publication matched, and then writes a sample. + * It quits when the publication matched has been reset again. + */ +MPT_ProcessEntry(hello_publisher, + MPT_Args(dds_domainid_t domainid, + const char *topic_name, + int sub_cnt, + const char *text)) +{ + HelloWorldData_Msg msg; + dds_listener_t *listener; + dds_entity_t participant; + dds_entity_t topic; + dds_entity_t writer; + dds_return_t rc; + dds_qos_t *qos; + int id = (int)ddsrt_getpid(); + + assert(topic_name); + assert(text); + + printf("=== [Publisher(%d)] Start(%d) ...\n", id, domainid); + + /* + * A reliable volatile sample, written after publication matched, can still + * be lost when the subscriber wasn't able to match its subscription yet. + * Use transient_local reliable to make sure the sample is received. + */ + qos = dds_create_qos(); + dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL); + dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10)); + + /* Use listener to get number of publications matched. */ + listener = dds_create_listener(NULL); + MPT_ASSERT_FATAL_NOT_NULL(listener, "Could not create listener"); + dds_lset_publication_matched(listener, publication_matched_cb); + + /* Create a Writer. */ + participant = dds_create_participant (domainid, NULL, NULL); + MPT_ASSERT_FATAL_GT(participant, 0, "Could not create participant: %s\n", dds_strretcode(-participant)); + + topic = dds_create_topic ( + participant, &HelloWorldData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT(topic, 0, "Could not create topic: %s\n", dds_strretcode(-topic)); + + writer = dds_create_writer (participant, topic, qos, listener); + MPT_ASSERT_FATAL_GT(writer, 0, "Could not create writer: %s\n", dds_strretcode(-writer)); + + /* Wait for expected nr of subscriber(s). */ + ddsrt_mutex_lock(&g_mutex); + while (g_publication_matched_count != sub_cnt) { + ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY); + } + ddsrt_mutex_unlock(&g_mutex); + + /* Write sample. */ + msg.userID = (int32_t)id; + msg.message = (char*)text; + printf("=== [Publisher(%d)] Send: { %d, %s }\n", id, msg.userID, msg.message); + rc = dds_write (writer, &msg); + MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Could not write sample\n"); + + /* Wait for subscriber(s) to have finished. */ + ddsrt_mutex_lock(&g_mutex); + while (g_publication_matched_count != 0) { + ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY); + } + ddsrt_mutex_unlock(&g_mutex); + + rc = dds_delete (participant); + MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Teardown failed\n"); + + dds_delete_listener(listener); + dds_delete_qos(qos); + + printf("=== [Publisher(%d)] Done\n", id); +} + + +/* + * The HelloWorld subscriber. + * It waits for sample(s) and checks the content. + */ +MPT_ProcessEntry(hello_subscriber, + MPT_Args(dds_domainid_t domainid, + const char *topic_name, + int sample_cnt, + const char *text)) +{ + HelloWorldData_Msg *msg; + void *samples[MAX_SAMPLES]; + dds_sample_info_t infos[MAX_SAMPLES]; + dds_listener_t *listener; + dds_entity_t participant; + dds_entity_t topic; + dds_entity_t reader; + dds_return_t rc; + dds_qos_t *qos; + int recv_cnt; + int id = (int)ddsrt_getpid(); + + assert(topic_name); + assert(text); + + printf("--- [Subscriber(%d)] Start(%d) ...\n", id, domainid); + + /* + * A reliable volatile sample, written after publication matched, can still + * be lost when the subscriber wasn't able to match its subscription yet. + * Use transient_local reliable to make sure the sample is received. + */ + qos = dds_create_qos(); + dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL); + dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10)); + + /* Use listener to get data available trigger. */ + listener = dds_create_listener(NULL); + MPT_ASSERT_FATAL_NOT_NULL(listener, "Could not create listener"); + dds_lset_data_available(listener, data_available_cb); + + /* Create a Reader. */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + MPT_ASSERT_FATAL_GT(participant, 0, "Could not create participant: %s\n", dds_strretcode(-participant)); + topic = dds_create_topic ( + participant, &HelloWorldData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT(topic, 0, "Could not create topic: %s\n", dds_strretcode(-topic)); + reader = dds_create_reader (participant, topic, qos, listener); + MPT_ASSERT_FATAL_GT(reader, 0, "Could not create reader: %s\n", dds_strretcode(-reader)); + + printf("--- [Subscriber(%d)] Waiting for %d sample(s) ...\n", id, sample_cnt); + + /* Initialize sample buffer, by pointing the void pointer within + * the buffer array to a valid sample memory location. */ + samples[0] = HelloWorldData_Msg__alloc (); + + /* Wait until expected nr of samples have been taken. */ + ddsrt_mutex_lock(&g_mutex); + recv_cnt = 0; + while (recv_cnt < sample_cnt) { + /* Use a take with mask to work around the #146 issue. */ + rc = dds_take_mask(reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES, DDS_NEW_VIEW_STATE); + MPT_ASSERT_GEQ(rc, 0, "Could not read: %s\n", dds_strretcode(-rc)); + + /* Check if we read some data and it is valid. */ + if ((rc > 0) && (infos[0].valid_data)) { + /* Print Message. */ + msg = (HelloWorldData_Msg*)samples[0]; + printf("--- [Subscriber(%d)] Received: { %d, %s }\n", id, + msg->userID, msg->message); + MPT_ASSERT_STR_EQ(msg->message, text, + "Messages do not match: \"%s\" vs \"%s\"\n", + msg->message, text); + recv_cnt++; + } else { + ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY); + } + } + ddsrt_mutex_unlock(&g_mutex); + + /* Free the data location. */ + HelloWorldData_Msg_free (samples[0], DDS_FREE_ALL); + + rc = dds_delete (participant); + MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Teardown failed\n"); + + dds_delete_listener(listener); + dds_delete_qos(qos); + + printf("--- [Subscriber(%d)] Done\n", id); +} diff --git a/src/mpt/tests/basic/procs/hello.h b/src/mpt/tests/basic/procs/hello.h new file mode 100644 index 0000000..b1d1772 --- /dev/null +++ b/src/mpt/tests/basic/procs/hello.h @@ -0,0 +1,52 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +/** @file + * + * @brief DDS C Communication Status API + * + * This header file defines the public API of the Communication Status in the + * Eclipse Cyclone DDS C language binding. + */ +#ifndef MPT_BASIC_PROCS_HELLO_H +#define MPT_BASIC_PROCS_HELLO_H + +#include +#include + +#include "dds/dds.h" +#include "mpt/mpt.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +void hello_init(void); +void hello_fini(void); + +MPT_ProcessEntry(hello_publisher, + MPT_Args(dds_domainid_t domainid, + const char *topic_name, + int sub_cnt, + const char *text)); + +MPT_ProcessEntry(hello_subscriber, + MPT_Args(dds_domainid_t domainid, + const char *topic_name, + int sample_cnt, + const char *text)); + +#if defined (__cplusplus) +} +#endif + +#endif /* MPT_BASIC_PROCS_HELLO_H */ diff --git a/src/mpt/tests/basic/procs/helloworlddata.idl b/src/mpt/tests/basic/procs/helloworlddata.idl new file mode 100644 index 0000000..9561d75 --- /dev/null +++ b/src/mpt/tests/basic/procs/helloworlddata.idl @@ -0,0 +1,9 @@ +module HelloWorldData +{ + struct Msg + { + long userID; + string message; + }; + #pragma keylist Msg userID +}; diff --git a/src/mpt/tests/self/CMakeLists.txt b/src/mpt/tests/self/CMakeLists.txt new file mode 100644 index 0000000..8203b5d --- /dev/null +++ b/src/mpt/tests/self/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include(${MPT_CMAKE}) + +message(STATUS "MPT selftest enabled: some test will fail deliberately") + +set(sources + "asserts.c" + "environments.c" + "fixtures.c" + "ipc.c" + "resources.c" + "usage.c") + +add_mpt_executable(mpt_self ${sources}) + diff --git a/src/mpt/tests/self/asserts.c b/src/mpt/tests/self/asserts.c new file mode 100644 index 0000000..72495a1 --- /dev/null +++ b/src/mpt/tests/self/asserts.c @@ -0,0 +1,711 @@ +#include +#include +#include "mpt/mpt.h" +#include "dds/ddsrt/time.h" + +static int dummy; + + + +/************************************************************ + * Test MPT_ASSERT + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT, MPT_Args(const char *exp, int cond)) +{ + assert(exp); + MPT_ASSERT(cond, "MPT_ASSERT(%d), 1st, expect: %s", cond, exp); + MPT_ASSERT(cond, "MPT_ASSERT(%d), 2nd, expect: %s", cond, exp); +} +MPT_TestProcess(MPT_ASSERT, pass, id, proc_MPT_ASSERT, MPT_ArgValues("PASS", 1)); +MPT_TestProcess(MPT_ASSERT, fail, id, proc_MPT_ASSERT, MPT_ArgValues("FAIL", 0)); +MPT_Test(MPT_ASSERT, pass, .xfail=false); +MPT_Test(MPT_ASSERT, fail, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FAIL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FAIL, MPT_NoArgs()) +{ + MPT_ASSERT_FAIL("MPT_ASSERT_FAIL(), 1st, expect a fail, always"); + MPT_ASSERT_FAIL("MPT_ASSERT_FAIL(), 2nd, expect a fail, always"); +} +MPT_TestProcess(MPT_ASSERT_FAIL, call, id, proc_MPT_ASSERT_FAIL, MPT_NoArgValues()); +MPT_Test(MPT_ASSERT_FAIL, call, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_EQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_EQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_EQ_int, eq, id, proc_MPT_ASSERT_EQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_EQ_int, lt, id, proc_MPT_ASSERT_EQ_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_EQ_int, gt, id, proc_MPT_ASSERT_EQ_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_EQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_EQ_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_EQ_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_EQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_EQ_double, eq, id, proc_MPT_ASSERT_EQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_EQ_double, lt, id, proc_MPT_ASSERT_EQ_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_EQ_double, gt, id, proc_MPT_ASSERT_EQ_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_EQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_EQ_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_EQ_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_NEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_NEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_NEQ_int, eq, id, proc_MPT_ASSERT_NEQ_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_NEQ_int, lt, id, proc_MPT_ASSERT_NEQ_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_NEQ_int, gt, id, proc_MPT_ASSERT_NEQ_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_NEQ_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_NEQ_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_NEQ_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_NEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_NEQ_double, eq, id, proc_MPT_ASSERT_NEQ_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_NEQ_double, lt, id, proc_MPT_ASSERT_NEQ_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_NEQ_double, gt, id, proc_MPT_ASSERT_NEQ_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_NEQ_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_NEQ_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_NEQ_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_LEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_LEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_LEQ_int, eq, id, proc_MPT_ASSERT_LEQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_LEQ_int, lt, id, proc_MPT_ASSERT_LEQ_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_LEQ_int, gt, id, proc_MPT_ASSERT_LEQ_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_LEQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_LEQ_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_LEQ_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_LEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_LEQ_double, eq, id, proc_MPT_ASSERT_LEQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_LEQ_double, lt, id, proc_MPT_ASSERT_LEQ_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_LEQ_double, gt, id, proc_MPT_ASSERT_LEQ_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_LEQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_LEQ_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_LEQ_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_GEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_GEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_GEQ_int, eq, id, proc_MPT_ASSERT_GEQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_GEQ_int, lt, id, proc_MPT_ASSERT_GEQ_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_GEQ_int, gt, id, proc_MPT_ASSERT_GEQ_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_GEQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_GEQ_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_GEQ_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_GEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_GEQ_double, eq, id, proc_MPT_ASSERT_GEQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_GEQ_double, lt, id, proc_MPT_ASSERT_GEQ_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_GEQ_double, gt, id, proc_MPT_ASSERT_GEQ_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_GEQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_GEQ_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_GEQ_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_LT + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_LT_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_LT_int, eq, id, proc_MPT_ASSERT_LT_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_LT_int, lt, id, proc_MPT_ASSERT_LT_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_LT_int, gt, id, proc_MPT_ASSERT_LT_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_LT_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_LT_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_LT_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_LT_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_LT_double, eq, id, proc_MPT_ASSERT_LT_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_LT_double, lt, id, proc_MPT_ASSERT_LT_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_LT_double, gt, id, proc_MPT_ASSERT_LT_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_LT_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_LT_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_LT_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_GT + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_GT_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%d, %d), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%d, %d), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_GT_int, eq, id, proc_MPT_ASSERT_GT_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_GT_int, lt, id, proc_MPT_ASSERT_GT_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_GT_int, gt, id, proc_MPT_ASSERT_GT_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_GT_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_GT_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_GT_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_GT_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%f, %f), 1st expect: %s", val1, val2, exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%f, %f), 2nd expect: %s", val1, val2, exp); +} +MPT_TestProcess(MPT_ASSERT_GT_double, eq, id, proc_MPT_ASSERT_GT_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_GT_double, lt, id, proc_MPT_ASSERT_GT_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_GT_double, gt, id, proc_MPT_ASSERT_GT_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_GT_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_GT_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_GT_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_NULL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_NULL, MPT_Args(const char *exp, const void* ptr)) +{ + assert(exp); + MPT_ASSERT_NULL(ptr, "MPT_ASSERT_NULL(%p), expect: %s", ptr, exp); +} +MPT_TestProcess(MPT_ASSERT_NULL, addr, id, proc_MPT_ASSERT_NULL, MPT_ArgValues("FAIL", &dummy)); +MPT_TestProcess(MPT_ASSERT_NULL, null, id, proc_MPT_ASSERT_NULL, MPT_ArgValues("PASS", NULL)); +MPT_Test(MPT_ASSERT_NULL, addr, .xfail=true); +MPT_Test(MPT_ASSERT_NULL, null, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_NOT_NULL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_NOT_NULL, MPT_Args(const char *exp, const void* ptr)) +{ + assert(exp); + MPT_ASSERT_NOT_NULL(ptr, "MPT_ASSERT_NOT_NULL(%p), expect: %s", ptr, exp); +} +MPT_TestProcess(MPT_ASSERT_NOT_NULL, addr, id, proc_MPT_ASSERT_NOT_NULL, MPT_ArgValues("PASS", &dummy)); +MPT_TestProcess(MPT_ASSERT_NOT_NULL, null, id, proc_MPT_ASSERT_NOT_NULL, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_NOT_NULL, addr, .xfail=false); +MPT_Test(MPT_ASSERT_NOT_NULL, null, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_STR_EQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_STR_EQ, MPT_Args(const char *exp, const char* val1, const char* val2)) +{ + assert(exp); + MPT_ASSERT_STR_EQ(val1, val2, "MPT_ASSERT_STR_EQ(%s, %s), expect: %s", + val1 ? val1 : "", + val2 ? val2 : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_STR_EQ, eq, id, proc_MPT_ASSERT_STR_EQ, MPT_ArgValues("PASS", "foo", "foo")); +MPT_TestProcess(MPT_ASSERT_STR_EQ, neq, id, proc_MPT_ASSERT_STR_EQ, MPT_ArgValues("FAIL", "foo", "bar")); +MPT_TestProcess(MPT_ASSERT_STR_EQ, null1, id, proc_MPT_ASSERT_STR_EQ, MPT_ArgValues("FAIL", NULL, "foo")); +MPT_TestProcess(MPT_ASSERT_STR_EQ, null2, id, proc_MPT_ASSERT_STR_EQ, MPT_ArgValues("FAIL", "foo", NULL)); +MPT_Test(MPT_ASSERT_STR_EQ, eq, .xfail=false); +MPT_Test(MPT_ASSERT_STR_EQ, neq, .xfail=true); +MPT_Test(MPT_ASSERT_STR_EQ, null1, .xfail=true); +MPT_Test(MPT_ASSERT_STR_EQ, null2, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_STR_NEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_STR_NEQ, MPT_Args(const char *exp, const char* val1, const char* val2)) +{ + assert(exp); + MPT_ASSERT_STR_NEQ(val1, val2, "MPT_ASSERT_STR_NEQ(%s, %s), expect: %s", + val1 ? val1 : "", + val2 ? val2 : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_STR_NEQ, eq, id, proc_MPT_ASSERT_STR_NEQ, MPT_ArgValues("FAIL", "foo", "foo")); +MPT_TestProcess(MPT_ASSERT_STR_NEQ, neq, id, proc_MPT_ASSERT_STR_NEQ, MPT_ArgValues("PASS", "foo", "bar")); +MPT_TestProcess(MPT_ASSERT_STR_NEQ, null1, id, proc_MPT_ASSERT_STR_NEQ, MPT_ArgValues("FAIL", NULL, "foo")); +MPT_TestProcess(MPT_ASSERT_STR_NEQ, null2, id, proc_MPT_ASSERT_STR_NEQ, MPT_ArgValues("FAIL", "foo", NULL)); +MPT_Test(MPT_ASSERT_STR_NEQ, eq, .xfail=true); +MPT_Test(MPT_ASSERT_STR_NEQ, neq, .xfail=false); +MPT_Test(MPT_ASSERT_STR_NEQ, null1, .xfail=true); +MPT_Test(MPT_ASSERT_STR_NEQ, null2, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_STR_EMPTY + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_STR_EMPTY, MPT_Args(const char *exp, const char* val)) +{ + assert(exp); + MPT_ASSERT_STR_EMPTY(val, "MPT_ASSERT_STR_EMPTY(%s), expect: %s", + val ? val : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_STR_EMPTY, nempty, id, proc_MPT_ASSERT_STR_EMPTY, MPT_ArgValues("FAIL", "foo")); +MPT_TestProcess(MPT_ASSERT_STR_EMPTY, empty, id, proc_MPT_ASSERT_STR_EMPTY, MPT_ArgValues("PASS", "")); +MPT_TestProcess(MPT_ASSERT_STR_EMPTY, null, id, proc_MPT_ASSERT_STR_EMPTY, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_STR_EMPTY, nempty, .xfail=true); +MPT_Test(MPT_ASSERT_STR_EMPTY, empty, .xfail=false); +MPT_Test(MPT_ASSERT_STR_EMPTY, null, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_STR_NOT_EMPTY + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_STR_NOT_EMPTY, MPT_Args(const char *exp, const char* val)) +{ + assert(exp); + MPT_ASSERT_STR_NOT_EMPTY(val, "MPT_ASSERT_STR_NOT_EMPTY(%s), expect: %s", + val ? val : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_STR_NOT_EMPTY, nempty, id, proc_MPT_ASSERT_STR_NOT_EMPTY, MPT_ArgValues("PASS", "foo")); +MPT_TestProcess(MPT_ASSERT_STR_NOT_EMPTY, empty, id, proc_MPT_ASSERT_STR_NOT_EMPTY, MPT_ArgValues("FAIL", "")); +MPT_TestProcess(MPT_ASSERT_STR_NOT_EMPTY, null, id, proc_MPT_ASSERT_STR_NOT_EMPTY, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_STR_NOT_EMPTY, nempty, .xfail=false); +MPT_Test(MPT_ASSERT_STR_NOT_EMPTY, empty, .xfail=true); +MPT_Test(MPT_ASSERT_STR_NOT_EMPTY, null, .xfail=true); + + + +/*****************************************************************************/ + + + +/************************************************************ + * Test MPT_ASSERT_FATAL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL, MPT_Args(const char *exp, int cond)) +{ + assert(exp); + MPT_ASSERT_FATAL(cond, "MPT_ASSERT_FATAL(%d), expect: %s", cond, exp); + MPT_ASSERT(cond, "MPT_ASSERT(%d) after a fatal", cond); +} + +MPT_TestProcess(MPT_ASSERT_FATAL, pass, id, proc_MPT_ASSERT_FATAL, MPT_ArgValues("PASS", 1)); +MPT_Test(MPT_ASSERT_FATAL, pass, .xfail=false); + +MPT_TestProcess(MPT_ASSERT_FATAL, fail, id, proc_MPT_ASSERT_FATAL, MPT_ArgValues("FAIL", 0)); +MPT_Test(MPT_ASSERT_FATAL, fail, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_FAIL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_FAIL, MPT_NoArgs()) +{ + MPT_ASSERT_FATAL_FAIL("MPT_ASSERT_FATAL_FAIL(), expect a fail, always"); + MPT_ASSERT_FAIL("MPT_ASSERT_FAIL() after a fatal"); +} + +MPT_TestProcess(MPT_ASSERT_FATAL_FAIL, fail, id, proc_MPT_ASSERT_FATAL_FAIL, MPT_NoArgValues()); +MPT_Test(MPT_ASSERT_FATAL_FAIL, fail, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_EQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_EQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_EQ(val1, val2, "MPT_ASSERT_FATAL_EQ(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_int, eq, id, proc_MPT_ASSERT_FATAL_EQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_int, lt, id, proc_MPT_ASSERT_FATAL_EQ_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_int, gt, id, proc_MPT_ASSERT_FATAL_EQ_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_EQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_EQ_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_EQ_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_EQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_EQ(val1, val2, "MPT_ASSERT_FATAL_EQ(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_EQ(val1, val2, "MPT_ASSERT_EQ(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_double, eq, id, proc_MPT_ASSERT_FATAL_EQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_double, lt, id, proc_MPT_ASSERT_FATAL_EQ_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_EQ_double, gt, id, proc_MPT_ASSERT_FATAL_EQ_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_EQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_EQ_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_EQ_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_NEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_NEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_NEQ(val1, val2, "MPT_ASSERT_FATAL_NEQ(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_int, eq, id, proc_MPT_ASSERT_FATAL_NEQ_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_int, lt, id, proc_MPT_ASSERT_FATAL_NEQ_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_int, gt, id, proc_MPT_ASSERT_FATAL_NEQ_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_NEQ_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_NEQ_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_NEQ_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_NEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_NEQ(val1, val2, "MPT_ASSERT_FATAL_NEQ(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_NEQ(val1, val2, "MPT_ASSERT_NEQ(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_double, eq, id, proc_MPT_ASSERT_FATAL_NEQ_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_double, lt, id, proc_MPT_ASSERT_FATAL_NEQ_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_NEQ_double, gt, id, proc_MPT_ASSERT_FATAL_NEQ_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_NEQ_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_NEQ_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_NEQ_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_LEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_LEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_LEQ(val1, val2, "MPT_ASSERT_FATAL_LEQ(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_int, eq, id, proc_MPT_ASSERT_FATAL_LEQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_int, lt, id, proc_MPT_ASSERT_FATAL_LEQ_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_int, gt, id, proc_MPT_ASSERT_FATAL_LEQ_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_LEQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LEQ_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LEQ_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_LEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_LEQ(val1, val2, "MPT_ASSERT_FATAL_LEQ(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_LEQ(val1, val2, "MPT_ASSERT_LEQ(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_double, eq, id, proc_MPT_ASSERT_FATAL_LEQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_double, lt, id, proc_MPT_ASSERT_FATAL_LEQ_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_LEQ_double, gt, id, proc_MPT_ASSERT_FATAL_LEQ_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_LEQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LEQ_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LEQ_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_GEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_GEQ_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_GEQ(val1, val2, "MPT_ASSERT_FATAL_GEQ(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_int, eq, id, proc_MPT_ASSERT_FATAL_GEQ_int, MPT_ArgValues("PASS", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_int, lt, id, proc_MPT_ASSERT_FATAL_GEQ_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_int, gt, id, proc_MPT_ASSERT_FATAL_GEQ_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_GEQ_int, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_GEQ_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GEQ_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_GEQ_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_GEQ(val1, val2, "MPT_ASSERT_FATAL_GEQ(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_GEQ(val1, val2, "MPT_ASSERT_GEQ(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_double, eq, id, proc_MPT_ASSERT_FATAL_GEQ_double, MPT_ArgValues("PASS", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_double, lt, id, proc_MPT_ASSERT_FATAL_GEQ_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_GEQ_double, gt, id, proc_MPT_ASSERT_FATAL_GEQ_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_GEQ_double, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_GEQ_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GEQ_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_LT + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_LT_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_LT(val1, val2, "MPT_ASSERT_FATAL_LT(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_LT_int, eq, id, proc_MPT_ASSERT_FATAL_LT_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_LT_int, lt, id, proc_MPT_ASSERT_FATAL_LT_int, MPT_ArgValues("PASS", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_LT_int, gt, id, proc_MPT_ASSERT_FATAL_LT_int, MPT_ArgValues("FAIL", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_LT_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_LT_int, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LT_int, gt, .xfail=true); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_LT_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_LT(val1, val2, "MPT_ASSERT_FATAL_LT(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_LT(val1, val2, "MPT_ASSERT_LT(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_LT_double, eq, id, proc_MPT_ASSERT_FATAL_LT_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_LT_double, lt, id, proc_MPT_ASSERT_FATAL_LT_double, MPT_ArgValues("PASS", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_LT_double, gt, id, proc_MPT_ASSERT_FATAL_LT_double, MPT_ArgValues("FAIL", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_LT_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_LT_double, lt, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_LT_double, gt, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_GT + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_GT_int, MPT_Args(const char *exp, int val1, int val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_GT(val1, val2, "MPT_ASSERT_FATAL_GT(%d, %d), expect: %s", val1, val2, exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%d, %d) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_GT_int, eq, id, proc_MPT_ASSERT_FATAL_GT_int, MPT_ArgValues("FAIL", 1, 1)); +MPT_TestProcess(MPT_ASSERT_FATAL_GT_int, lt, id, proc_MPT_ASSERT_FATAL_GT_int, MPT_ArgValues("FAIL", 1, 2)); +MPT_TestProcess(MPT_ASSERT_FATAL_GT_int, gt, id, proc_MPT_ASSERT_FATAL_GT_int, MPT_ArgValues("PASS", 3, 2)); +MPT_Test(MPT_ASSERT_FATAL_GT_int, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GT_int, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GT_int, gt, .xfail=false); + + +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_GT_double, MPT_Args(const char *exp, double val1, double val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_GT(val1, val2, "MPT_ASSERT_FATAL_GT(%f, %f), expect: %s", val1, val2, exp); + MPT_ASSERT_GT(val1, val2, "MPT_ASSERT_GT(%f, %f) after a fatal", val1, val2); +} +MPT_TestProcess(MPT_ASSERT_FATAL_GT_double, eq, id, proc_MPT_ASSERT_FATAL_GT_double, MPT_ArgValues("FAIL", 1.1, 1.1)); +MPT_TestProcess(MPT_ASSERT_FATAL_GT_double, lt, id, proc_MPT_ASSERT_FATAL_GT_double, MPT_ArgValues("FAIL", 1.1, 1.2)); +MPT_TestProcess(MPT_ASSERT_FATAL_GT_double, gt, id, proc_MPT_ASSERT_FATAL_GT_double, MPT_ArgValues("PASS", 1.3, 1.2)); +MPT_Test(MPT_ASSERT_FATAL_GT_double, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GT_double, lt, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_GT_double, gt, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_NULL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_NULL, MPT_Args(const char *exp, const void* ptr)) +{ + assert(exp); + MPT_ASSERT_FATAL_NULL(ptr, "MPT_ASSERT_FATAL_NULL(%p), expect: %s", ptr, exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_NULL, addr, id, proc_MPT_ASSERT_FATAL_NULL, MPT_ArgValues("FAIL", &dummy)); +MPT_TestProcess(MPT_ASSERT_FATAL_NULL, null, id, proc_MPT_ASSERT_FATAL_NULL, MPT_ArgValues("PASS", NULL)); +MPT_Test(MPT_ASSERT_FATAL_NULL, addr, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_NULL, null, .xfail=false); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_NOT_NULL + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_NOT_NULL, MPT_Args(const char *exp, const void* ptr)) +{ + assert(exp); + MPT_ASSERT_FATAL_NOT_NULL(ptr, "MPT_ASSERT_FATAL_NOT_NULL(%p), expect: %s", ptr, exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_NOT_NULL, addr, id, proc_MPT_ASSERT_FATAL_NOT_NULL, MPT_ArgValues("PASS", &dummy)); +MPT_TestProcess(MPT_ASSERT_FATAL_NOT_NULL, null, id, proc_MPT_ASSERT_FATAL_NOT_NULL, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_FATAL_NOT_NULL, addr, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_NOT_NULL, null, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_STR_EQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_STR_EQ, MPT_Args(const char *exp, const char* val1, const char* val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_STR_EQ(val1, val2, "MPT_ASSERT_FATAL_STR_EQ(%s, %s), expect: %s", + val1 ? val1 : "", + val2 ? val2 : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EQ, eq, id, proc_MPT_ASSERT_FATAL_STR_EQ, MPT_ArgValues("PASS", "foo", "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EQ, neq, id, proc_MPT_ASSERT_FATAL_STR_EQ, MPT_ArgValues("FAIL", "foo", "bar")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EQ, null1, id, proc_MPT_ASSERT_FATAL_STR_EQ, MPT_ArgValues("FAIL", NULL, "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EQ, null2, id, proc_MPT_ASSERT_FATAL_STR_EQ, MPT_ArgValues("FAIL", "foo", NULL)); +MPT_Test(MPT_ASSERT_FATAL_STR_EQ, eq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_STR_EQ, neq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_EQ, null1, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_EQ, null2, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_STR_NEQ + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_STR_NEQ, MPT_Args(const char *exp, const char* val1, const char* val2)) +{ + assert(exp); + MPT_ASSERT_FATAL_STR_NEQ(val1, val2, "MPT_ASSERT_FATAL_STR_NEQ(%s, %s), expect: %s", + val1 ? val1 : "", + val2 ? val2 : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NEQ, eq, id, proc_MPT_ASSERT_FATAL_STR_NEQ, MPT_ArgValues("FAIL", "foo", "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NEQ, neq, id, proc_MPT_ASSERT_FATAL_STR_NEQ, MPT_ArgValues("PASS", "foo", "bar")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NEQ, null1, id, proc_MPT_ASSERT_FATAL_STR_NEQ, MPT_ArgValues("FAIL", NULL, "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NEQ, null2, id, proc_MPT_ASSERT_FATAL_STR_NEQ, MPT_ArgValues("FAIL", "foo", NULL)); +MPT_Test(MPT_ASSERT_FATAL_STR_NEQ, eq, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_NEQ, neq, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_STR_NEQ, null1, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_NEQ, null2, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_STR_EMPTY + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_STR_EMPTY, MPT_Args(const char *exp, const char* val)) +{ + assert(exp); + MPT_ASSERT_FATAL_STR_EMPTY(val, "MPT_ASSERT_FATAL_STR_EMPTY(%s), expect: %s", + val ? val : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EMPTY, nempty, id, proc_MPT_ASSERT_FATAL_STR_EMPTY, MPT_ArgValues("FAIL", "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EMPTY, empty, id, proc_MPT_ASSERT_FATAL_STR_EMPTY, MPT_ArgValues("PASS", "")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_EMPTY, null, id, proc_MPT_ASSERT_FATAL_STR_EMPTY, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_FATAL_STR_EMPTY, nempty, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_EMPTY, empty, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_STR_EMPTY, null, .xfail=true); + + + +/************************************************************ + * Test MPT_ASSERT_FATAL_STR_NOT_EMPTY + ************************************************************/ +MPT_ProcessEntry(proc_MPT_ASSERT_FATAL_STR_NOT_EMPTY, MPT_Args(const char *exp, const char* val)) +{ + assert(exp); + MPT_ASSERT_FATAL_STR_NOT_EMPTY(val, "MPT_ASSERT_FATAL_STR_NOT_EMPTY(%s), expect: %s", + val ? val : "", + exp); +} +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NOT_EMPTY, nempty, id, proc_MPT_ASSERT_FATAL_STR_NOT_EMPTY, MPT_ArgValues("PASS", "foo")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NOT_EMPTY, empty, id, proc_MPT_ASSERT_FATAL_STR_NOT_EMPTY, MPT_ArgValues("FAIL", "")); +MPT_TestProcess(MPT_ASSERT_FATAL_STR_NOT_EMPTY, null, id, proc_MPT_ASSERT_FATAL_STR_NOT_EMPTY, MPT_ArgValues("FAIL", NULL)); +MPT_Test(MPT_ASSERT_FATAL_STR_NOT_EMPTY, nempty, .xfail=false); +MPT_Test(MPT_ASSERT_FATAL_STR_NOT_EMPTY, empty, .xfail=true); +MPT_Test(MPT_ASSERT_FATAL_STR_NOT_EMPTY, null, .xfail=true); + + + +/*****************************************************************************/ + + + +/************************************************************ + * Test propagation, + * Check if failure/success is actually propagated to ctest. + ************************************************************/ +MPT_ProcessEntry(proc_propagation, MPT_Args(const char *exp, int cond, dds_duration_t delay)) +{ + assert(exp); + if (delay > 0) { + dds_sleepfor(delay); + } + MPT_ASSERT(cond, "MPT_ASSERT(%d), expect: %s", cond, exp); +} +/* This should pass in the ctest results. */ +MPT_TestProcess(propagation, pass, id1, proc_propagation, MPT_ArgValues("PASS", 1, 0)); +MPT_TestProcess(propagation, pass, id2, proc_propagation, MPT_ArgValues("PASS", 1, 0)); +MPT_Test(propagation, pass); +/* This should fail in the ctest results. */ +MPT_TestProcess(propagation, fail_1st, id1, proc_propagation, MPT_ArgValues("FAIL", 0, 0)); +MPT_TestProcess(propagation, fail_1st, id2, proc_propagation, MPT_ArgValues("PASS", 1, DDS_SECS(1))); +MPT_Test(propagation, fail_1st); +/* This should fail in the ctest results. */ +MPT_TestProcess(propagation, fail_2nd, id1, proc_propagation, MPT_ArgValues("PASS", 1, 0)); +MPT_TestProcess(propagation, fail_2nd, id2, proc_propagation, MPT_ArgValues("FAIL", 0, DDS_SECS(1))); +MPT_Test(propagation, fail_2nd); + diff --git a/src/mpt/tests/self/environments.c b/src/mpt/tests/self/environments.c new file mode 100644 index 0000000..9b6dc97 --- /dev/null +++ b/src/mpt/tests/self/environments.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include "mpt/mpt.h" +#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */ +#include "dds/ddsrt/environ.h" + + + +/************************************************************ + * Process + ************************************************************/ +MPT_ProcessEntry(proc_environments, MPT_Args(mpt_env_t *exp)) +{ + assert(exp); + while ((exp->name != NULL) && (exp->value != NULL)) { + /* The environment variable value should match the expected value. */ + char *ptr = NULL; + ddsrt_getenv(exp->name, &ptr); + if (ptr) { + MPT_ASSERT((strcmp(exp->value, ptr) == 0), "%s: found \"%s\", expected \"%s\"", exp->name, ptr, exp->value); + } else { + MPT_ASSERT(0, "Expected \"%s\" not found in environment", exp->name); + } + exp++; + } +} + + + +/************************************************************ + * Basic environment tests + ************************************************************/ +static mpt_env_t environ_basic[] = { + { "MY_ENV_VAR1", "1" }, + { "MY_ENV_VAR2", "2" }, + { NULL, NULL } +}; + +MPT_TestProcess(environment, proc, id, proc_environments, MPT_ArgValues(environ_basic), .environment=environ_basic); +MPT_Test(environment, proc); + +MPT_TestProcess(environment, test, id, proc_environments, MPT_ArgValues(environ_basic)); +MPT_Test(environment, test, .environment=environ_basic); + + + +/************************************************************ + * Expanding variables environment tests + ************************************************************/ +static mpt_env_t environ_expand[] = { + { "1", "b" }, + { "2", "${1}l" }, + { "3", "${2}aat" }, + { "4", "bla${1}${2}a${3}" }, + { NULL, NULL } +}; +static mpt_env_t expect_expand[] = { + { "1", "b" }, + { "2", "bl" }, + { "3", "blaat" }, + { "4", "blabblablaat" }, + { NULL, NULL } +}; + +MPT_TestProcess(environment, expand_proc, id, proc_environments, MPT_ArgValues(expect_expand), .environment=environ_expand); +MPT_Test(environment, expand_proc); + +MPT_TestProcess(environment, expand_test, id, proc_environments, MPT_ArgValues(expect_expand)); +MPT_Test(environment, expand_test, .environment=environ_expand); + + + +/************************************************************ + * Environment inheritance test + ************************************************************/ +static mpt_env_t environ_test[] = { + { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/self/etc" }, + { "OVERRULE", "NO" }, + { NULL, NULL } +}; +static mpt_env_t environ_proc[] = { + { "CYCLONE_URI", "file://${ETC_DIR}/ospl.xml" }, + { "OVERRULE", "YES" }, + { "EXTRA", "proc" }, + { NULL, NULL } +}; +static mpt_env_t environ_test_proc[] = { + { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/self/etc" }, + { "CYCLONE_URI", "file://"MPT_SOURCE_ROOT_DIR"/tests/self/etc/ospl.xml" }, + { "OVERRULE", "YES" }, + { "EXTRA", "proc" }, + { NULL, NULL } +}; +MPT_TestProcess(environment, inheritance, id, proc_environments, MPT_ArgValues(environ_test_proc), .environment=environ_proc); +MPT_Test(environment, inheritance, .environment=environ_test); diff --git a/src/mpt/tests/self/etc/file b/src/mpt/tests/self/etc/file new file mode 100644 index 0000000..e69de29 diff --git a/src/mpt/tests/self/fixtures.c b/src/mpt/tests/self/fixtures.c new file mode 100644 index 0000000..25b5782 --- /dev/null +++ b/src/mpt/tests/self/fixtures.c @@ -0,0 +1,72 @@ +#include +#include "mpt/mpt.h" +#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */ +#include "dds/ddsrt/time.h" + + + +/************************************************************ + * Support functions + ************************************************************/ +static int g_initcnt = 0; +static void init_inc(void) +{ + g_initcnt++; +}; + + + +/************************************************************ + * Processes + ************************************************************/ +MPT_ProcessEntry(proc_initcnt, MPT_Args(int init)) +{ + MPT_ASSERT((g_initcnt == init), "init count: %d vs %d", g_initcnt, init); +} + +MPT_ProcessEntry(proc_sleep, MPT_Args(dds_duration_t delay)) +{ + MPT_ASSERT((delay > 0), "basically just to satisfy the compiler"); + dds_sleepfor(delay); +} + + + +/************************************************************ + * Init fixture tests + ************************************************************/ +MPT_TestProcess(init, none, id, proc_initcnt, MPT_ArgValues(0)); +MPT_Test(init, none); + +MPT_TestProcess(init, null, id, proc_initcnt, MPT_ArgValues(0), .init=NULL); +MPT_Test(init, null, .init=NULL); + +MPT_TestProcess(init, proc, id, proc_initcnt, MPT_ArgValues(1), .init=init_inc); +MPT_Test(init, proc); + +MPT_TestProcess(init, test, id, proc_initcnt, MPT_ArgValues(1)); +MPT_Test(init, test, .init=init_inc); + +MPT_TestProcess(init, test_proc, id, proc_initcnt, MPT_ArgValues(2), .init=init_inc); +MPT_Test(init, test_proc, .init=init_inc); + + + +/************************************************************ + * Disable fixture tests + ************************************************************/ +MPT_TestProcess(disabled, _true, id, proc_initcnt, MPT_ArgValues(0)); +MPT_Test(disabled, _true, .disabled=true); + +MPT_TestProcess(disabled, _false, id, proc_initcnt, MPT_ArgValues(0)); +MPT_Test(disabled, _false, .disabled=false); + + + +/************************************************************ + * Timeout fixture tests + ************************************************************/ +/* See if a child process is killed when the parent is killed. + * This can only really be done manually, unfortunately. */ +MPT_TestProcess(timeout, child_culling, id, proc_sleep, MPT_ArgValues(DDS_SECS(120))); +MPT_Test(timeout, child_culling, .timeout=1); diff --git a/src/mpt/tests/self/ipc.c b/src/mpt/tests/self/ipc.c new file mode 100644 index 0000000..932c6e6 --- /dev/null +++ b/src/mpt/tests/self/ipc.c @@ -0,0 +1,29 @@ +#include +#include "mpt/mpt.h" + + + +/************************************************************ + * Processes + ************************************************************/ +MPT_ProcessEntry(proc_ipc_send, MPT_NoArgs()) +{ + /* This will fail and cause an internal MPT assert as long + * as IPC is not yet implemented. */ + MPT_Send("todo: implement"); +} +MPT_ProcessEntry(proc_ipc_wait, MPT_NoArgs()) +{ + /* This will fail and cause an internal MPT assert as long + * as IPC is not yet implemented. */ + MPT_Wait("todo: implement"); +} + + + +/************************************************************ + * Tests + ************************************************************/ +MPT_TestProcess(ipc, TODO, id1, proc_ipc_send, MPT_NoArgValues()); +MPT_TestProcess(ipc, TODO, id2, proc_ipc_wait, MPT_NoArgValues()); +MPT_Test(ipc, TODO); diff --git a/src/mpt/tests/self/resources.c b/src/mpt/tests/self/resources.c new file mode 100644 index 0000000..9cba731 --- /dev/null +++ b/src/mpt/tests/self/resources.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "mpt/mpt.h" +#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */ + +/************************************************************ + * Processes + ************************************************************/ +MPT_ProcessEntry(proc_file, MPT_NoArgs()) +{ + const char *test_file = MPT_SOURCE_ROOT_DIR"/tests/self/etc/file"; +#if _WIN32 + struct _stat buffer; + int ret = _stat(test_file,&buffer); +#else + struct stat buffer; + int ret = stat(test_file,&buffer); +#endif + MPT_ASSERT((ret == 0), "%s", test_file); +} + + + +/************************************************************ + * Test if MPT_SOURCE_ROOT_DIR is a valid location. + ************************************************************/ +MPT_TestProcess(resources, root_dir, id, proc_file, MPT_NoArgValues()); +MPT_Test(resources, root_dir); + diff --git a/src/mpt/tests/self/usage.c b/src/mpt/tests/self/usage.c new file mode 100644 index 0000000..1621810 --- /dev/null +++ b/src/mpt/tests/self/usage.c @@ -0,0 +1,186 @@ +#include +#include "mpt/mpt.h" +#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */ + + +/****************************************************************************** + * First, we need a process entry-point that can be used in tests. + *****************************************************************************/ +/* | name | arguments | */ +MPT_ProcessEntry(proc_noargs, MPT_NoArgs()) +{ + // Do stuff + + // The test processes will use asserts to indicate success/failures. + MPT_ASSERT(1, "The problem is: %s", "existential crisis"); + + // No need to return anything, that's handled by the assert calls. +} + +/****************************************************************************** + * A process entry-point can have arguments. + *****************************************************************************/ +/* | name | arguments | */ +MPT_ProcessEntry(proc_args, MPT_Args(int domain, const char* text)) +{ + int expected = 1; + MPT_ASSERT(expected == domain, "proc_args(%d, %s)", domain, text); +} + +/****************************************************************************** + * Process entry-points can communicate to be able to sync fi. + *****************************************************************************/ +MPT_ProcessEntry(proc_recv, MPT_NoArgs()) +{ + /* This will wait until another process sends the same string. */ + MPT_Wait("some state reached"); +} +MPT_ProcessEntry(proc_send, MPT_NoArgs()) +{ + /* If this fails, an internal MPT_ASSERT will be triggered. + * The same is true for MPT_Wait(). */ + MPT_Send("some state reached"); +} + + + +/****************************************************************************** + * Test: suitename_testA + ****************************************************************************** + * A simple test that starts two processes. Because a test can use the same + * process entry-point to start multiple processes, each process has to have + * its own unique id within the test. + */ +/* | process identification | entry-point | arguments | */ +MPT_TestProcess(suitename, testA, id1, proc_noargs, MPT_NoArgValues()); +MPT_TestProcess(suitename, testA, id2, proc_noargs, MPT_NoArgValues()); +MPT_Test(suitename, testA); + + + + +/****************************************************************************** + * Test: suitename_testB + ****************************************************************************** + * Of course, different processes can be started as well. + * Argument values are provided per test process. + */ +MPT_TestProcess(suitename, testB, id1, proc_noargs, MPT_NoArgValues( )); +MPT_TestProcess(suitename, testB, id2, proc_args, MPT_ArgValues(1, "2")); +MPT_TestProcess(suitename, testB, id3, proc_args, MPT_ArgValues(1, "3")); +MPT_Test(suitename, testB); + + + + +/****************************************************************************** + * Test: suitename_testC + ****************************************************************************** + * The processes can have different or equal 'system environments'. + */ +mpt_env_t environment_C1[] = { + { "CYCLONEDDS_URI", "file://config1.xml" }, + { "PERMISSIONS", "file://permissions.p7s" }, + { "GOVERNANCE", "file://governance.p7s" }, + { NULL, NULL } +}; +mpt_env_t environment_C2[] = { + { "CYCLONEDDS_URI", "file://config2.xml" }, + { "PERMISSIONS", "file://permissions.p7s" }, + { "GOVERNANCE", "file://governance.p7s" }, + { NULL, NULL } +}; +MPT_TestProcess(suitename, testC, id1, proc_noargs, MPT_NoArgValues(), .environment=environment_C1); +MPT_TestProcess(suitename, testC, id2, proc_noargs, MPT_NoArgValues(), .environment=environment_C1); +MPT_TestProcess(suitename, testC, id3, proc_noargs, MPT_NoArgValues(), .environment=environment_C2); +MPT_Test(suitename, testC); + + + + +/****************************************************************************** + * Test: suitename_testD + ****************************************************************************** + * The two environments in the previous example are partly the same. + * It's possible set the environment on test level. The environment variables + * related to the test are set before the ones related to a process. This + * means that a process can overrule variables. + * + * The following test is the same as the previous one. + */ +mpt_env_t environment_D1[] = { + { "CYCLONEDDS_URI", "file://config1.xml" }, + { "PERMISSIONS", "file://permissions.p7s" }, + { "GOVERNANCE", "file://governance.p7s" }, + { NULL, NULL } +}; +mpt_env_t environment_D2[] = { + { "CYCLONEDDS_URI", "file://config2.xml" }, + { NULL, NULL } +}; +MPT_TestProcess(suitename, testD, id1, proc_noargs, MPT_NoArgValues()); +MPT_TestProcess(suitename, testD, id2, proc_noargs, MPT_NoArgValues()); +MPT_TestProcess(suitename, testD, id3, proc_noargs, MPT_NoArgValues(), .environment=environment_D2); +MPT_Test(suitename, testD, .environment=environment_D1); + + + + +/****************************************************************************** + * Test: suitename_testE + ****************************************************************************** + * Environment variables will be expanded. + * Also, the MPT_SOURCE_ROOT_DIR define contains a string to that particular + * directory. + * This can be combined to easily point to files. + */ +mpt_env_t environment_E[] = { + { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/self/etc" }, + { "CYCLONEDDS_URI", "file://${ETC_DIR}/config.xml" }, + { NULL, NULL } +}; +MPT_TestProcess(suitename, testE, id, proc_noargs, MPT_NoArgValues(), .environment=environment_E); +MPT_Test(suitename, testE); + + + + +/****************************************************************************** + * Test: suitename_testF + ****************************************************************************** + * The processes and tests can use init/fini fixtures. + * The test init is executed before the process init. + * The process fini is executed before the test fini. + */ +void proc_setup(void) { /* do stuff */ } +void proc_teardown(void) { /* do stuff */ } +void test_setup(void) { /* do stuff */ } +void test_teardown(void) { /* do stuff */ } +MPT_TestProcess(suitename, testF, id1, proc_noargs, MPT_NoArgValues(), .init=proc_setup); +MPT_TestProcess(suitename, testF, id2, proc_noargs, MPT_NoArgValues(), .fini=proc_teardown); +MPT_TestProcess(suitename, testF, id3, proc_noargs, MPT_NoArgValues(), .init=proc_setup, .fini=proc_teardown); +MPT_Test(suitename, testF, .init=test_setup, .fini=test_teardown); + + + + +/****************************************************************************** + * Test: suitename_testG + ****************************************************************************** + * The timeout and disable options are handled by test fixtures. + */ +MPT_TestProcess(suitename, testG, id1, proc_noargs, MPT_NoArgValues()); +MPT_TestProcess(suitename, testG, id2, proc_noargs, MPT_NoArgValues()); +MPT_Test(suitename, testG, .timeout=10, .disabled=true); + + + + +/****************************************************************************** + * Test: suitename_testH + ****************************************************************************** + * See the process entries to notice the MPT Send/Wait IPC. + */ +MPT_TestProcess(suitename, testH, id1, proc_recv, MPT_NoArgValues()); +MPT_TestProcess(suitename, testH, id2, proc_send, MPT_NoArgValues()); +MPT_Test(suitename, testH);