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.
+
+
+
+
+#### 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.
+
+
+
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);