Merge pull request #152 from martinbremmer/mptproto3
Multi Process Testing framework
This commit is contained in:
		
						commit
						bf79e12e10
					
				
					 44 changed files with 4458 additions and 69 deletions
				
			
		
							
								
								
									
										86
									
								
								docs/dev/mpt_req.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								docs/dev/mpt_req.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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.<br>
 | 
				
			||||||
 | 
					  [1.1/1.2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The files that contain the tests, should be easy to understand and focus on
 | 
				
			||||||
 | 
					  the tests themselves.<br>
 | 
				
			||||||
 | 
					  [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.<br>
 | 
				
			||||||
 | 
					  [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.<br>
 | 
				
			||||||
 | 
					  [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.<br>
 | 
				
			||||||
 | 
					  [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.<br>
 | 
				
			||||||
 | 
					  [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.<br>
 | 
				
			||||||
 | 
					  [1.5]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								docs/dev/multi_process_testing.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								docs/dev/multi_process_testing.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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.<br>
 | 
				
			||||||
 | 
					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.<br>
 | 
				
			||||||
 | 
					A suite can have multiple tests and tests can have multiple processes.<br>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This results in the following tree quite naturally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="pictures/mpt_tree.png" alt="Suite-Test-Process tree">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Test execution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are 3 main ways to start an MPT application.
 | 
				
			||||||
 | 
					1. Without argument.<br>
 | 
				
			||||||
 | 
					   All tests will be run.
 | 
				
			||||||
 | 
					2. With suite and/or test name patterns as arguments.<br>
 | 
				
			||||||
 | 
					   A subset of tests will be run depending on the provided patterns.<br>
 | 
				
			||||||
 | 
					   This allows ctest to execute single tests.
 | 
				
			||||||
 | 
					3. With a specific suite/test/process combination as arguments.<br>
 | 
				
			||||||
 | 
					   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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="pictures/mpt_flow.png" alt="MPT application flow">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docs/dev/pictures/mpt_flow.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/dev/pictures/mpt_flow.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/dev/pictures/mpt_tree.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/dev/pictures/mpt_tree.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 19 KiB  | 
| 
						 | 
					@ -186,5 +186,11 @@ endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_subdirectory(examples)
 | 
					add_subdirectory(examples)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (BUILD_TESTING)
 | 
				
			||||||
 | 
					  # Multi Process Tests
 | 
				
			||||||
 | 
					  add_subdirectory(mpt)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Pull-in CPack and support for generating <Package>Config.cmake and packages.
 | 
					# Pull-in CPack and support for generating <Package>Config.cmake and packages.
 | 
				
			||||||
include(Packaging)
 | 
					include(Packaging)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "dds/ddsrt/string.h"
 | 
					#include "dds/ddsrt/string.h"
 | 
				
			||||||
#include "dds/ddsrt/strtod.h"
 | 
					#include "dds/ddsrt/strtod.h"
 | 
				
			||||||
#include "dds/ddsrt/misc.h"
 | 
					#include "dds/ddsrt/misc.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/environ.h"
 | 
				
			||||||
#include "dds/ddsi/q_config.h"
 | 
					#include "dds/ddsi/q_config.h"
 | 
				
			||||||
#include "dds/ddsi/q_log.h"
 | 
					#include "dds/ddsi/q_log.h"
 | 
				
			||||||
#include "dds/ddsrt/avl.h"
 | 
					#include "dds/ddsrt/avl.h"
 | 
				
			||||||
| 
						 | 
					@ -32,7 +33,6 @@
 | 
				
			||||||
#include "dds/ddsi/q_error.h"
 | 
					#include "dds/ddsi/q_error.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "dds/ddsrt/xmlparser.h"
 | 
					#include "dds/ddsrt/xmlparser.h"
 | 
				
			||||||
#include "dds/ddsrt/expand_envvars.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "dds/version.h"
 | 
					#include "dds/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,13 +74,11 @@ list(APPEND sources
 | 
				
			||||||
  "${source_path}/io.c"
 | 
					  "${source_path}/io.c"
 | 
				
			||||||
  "${source_path}/log.c"
 | 
					  "${source_path}/log.c"
 | 
				
			||||||
  "${source_path}/retcode.c"
 | 
					  "${source_path}/retcode.c"
 | 
				
			||||||
  "${source_path}/process.c"
 | 
					 | 
				
			||||||
  "${source_path}/strtod.c"
 | 
					  "${source_path}/strtod.c"
 | 
				
			||||||
  "${source_path}/strtol.c")
 | 
					  "${source_path}/strtol.c")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
list(APPEND headers
 | 
					list(APPEND headers
 | 
				
			||||||
  "${source_path}/dds/ddsrt/avl.h"
 | 
					  "${source_path}/dds/ddsrt/avl.h"
 | 
				
			||||||
  "${source_path}/dds/ddsrt/expand_envvars.h"
 | 
					 | 
				
			||||||
  "${source_path}/dds/ddsrt/fibheap.h"
 | 
					  "${source_path}/dds/ddsrt/fibheap.h"
 | 
				
			||||||
  "${source_path}/dds/ddsrt/hopscotch.h"
 | 
					  "${source_path}/dds/ddsrt/hopscotch.h"
 | 
				
			||||||
  "${source_path}/dds/ddsrt/thread_pool.h")
 | 
					  "${source_path}/dds/ddsrt/thread_pool.h")
 | 
				
			||||||
| 
						 | 
					@ -104,7 +102,7 @@ list(APPEND sources
 | 
				
			||||||
# network stack. In order to mix-and-match various compilers, architectures,
 | 
					# network stack. In order to mix-and-match various compilers, architectures,
 | 
				
			||||||
# operating systems, etc input from the build system is required.
 | 
					# operating systems, etc input from the build system is required.
 | 
				
			||||||
foreach(feature atomics cdtors environ heap ifaddrs random rusage
 | 
					foreach(feature atomics cdtors environ heap ifaddrs random rusage
 | 
				
			||||||
                sockets string sync threads time md5)
 | 
					                sockets string sync threads time md5 process)
 | 
				
			||||||
  if(EXISTS "${include_path}/dds/ddsrt/${feature}.h")
 | 
					  if(EXISTS "${include_path}/dds/ddsrt/${feature}.h")
 | 
				
			||||||
    list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h")
 | 
					    list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h")
 | 
				
			||||||
    file(GLOB
 | 
					    file(GLOB
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,6 +96,50 @@ ddsrt_unsetenv(
 | 
				
			||||||
  const char *name)
 | 
					  const char *name)
 | 
				
			||||||
ddsrt_nonnull_all;
 | 
					ddsrt_nonnull_all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Expand environment variables within string.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The result string should be freed with ddsrt_free().
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]  string  String to expand.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns Allocated char*.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval NULL
 | 
				
			||||||
 | 
					 *             Expansion failed.
 | 
				
			||||||
 | 
					 * @retval Pointer
 | 
				
			||||||
 | 
					 *             Copy of the string argument with the environment
 | 
				
			||||||
 | 
					 *             variables expanded.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT char*
 | 
				
			||||||
 | 
					ddsrt_expand_envvars(
 | 
				
			||||||
 | 
					  const char *string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Expand environment variables within string.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, $ and \
 | 
				
			||||||
 | 
					 * can be escaped with \.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The result string should be freed with ddsrt_free().
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]  string  String to expand.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns Allocated char*.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval NULL
 | 
				
			||||||
 | 
					 *             Expansion failed.
 | 
				
			||||||
 | 
					 * @retval Pointer
 | 
				
			||||||
 | 
					 *             Copy of the string argument with the environment
 | 
				
			||||||
 | 
					 *             variables expanded.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT char*
 | 
				
			||||||
 | 
					ddsrt_expand_envvars_sh(
 | 
				
			||||||
 | 
					  const char *string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__cplusplus)
 | 
					#if defined(__cplusplus)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 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 DDSRT_EXPAND_ENVVARS_H
 | 
					 | 
				
			||||||
#define DDSRT_EXPAND_ENVVARS_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "dds/export.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined (__cplusplus)
 | 
					 | 
				
			||||||
extern "C" {
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */
 | 
					 | 
				
			||||||
    DDS_EXPORT char *ddsrt_expand_envvars(const char *string);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, $ and \ can be escaped with \ */
 | 
					 | 
				
			||||||
    DDS_EXPORT char *ddsrt_expand_envvars_sh(const char *string);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined (__cplusplus)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ typedef struct {
 | 
				
			||||||
/** Function signature that log and trace callbacks must adhere too. */
 | 
					/** Function signature that log and trace callbacks must adhere too. */
 | 
				
			||||||
typedef void(*dds_log_write_fn_t)(void *, const dds_log_data_t *);
 | 
					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.
 | 
					 * @brief Get currently enabled log and trace categories.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,11 +13,9 @@
 | 
				
			||||||
#define DDSRT_PROCESS_H
 | 
					#define DDSRT_PROCESS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "dds/export.h"
 | 
					#include "dds/export.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/time.h"
 | 
				
			||||||
#include "dds/ddsrt/types.h"
 | 
					#include "dds/ddsrt/types.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/retcode.h"
 | 
				
			||||||
#if defined (__cplusplus)
 | 
					 | 
				
			||||||
extern "C" {
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
typedef DWORD ddsrt_pid_t;
 | 
					typedef DWORD ddsrt_pid_t;
 | 
				
			||||||
| 
						 | 
					@ -33,6 +31,11 @@ typedef pid_t ddsrt_pid_t;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif /* _WIN32 */
 | 
					#endif /* _WIN32 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined (__cplusplus)
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Return process ID (PID) of the calling process.
 | 
					 * @brief Return process ID (PID) of the calling process.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -41,6 +44,168 @@ typedef pid_t ddsrt_pid_t;
 | 
				
			||||||
DDS_EXPORT ddsrt_pid_t
 | 
					DDS_EXPORT ddsrt_pid_t
 | 
				
			||||||
ddsrt_getpid(void);
 | 
					ddsrt_getpid(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Create new process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Creates a new process using the provided executable file. It will have
 | 
				
			||||||
 | 
					 * default priority and scheduling.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Process arguments are represented by argv, which can be null. If argv is
 | 
				
			||||||
 | 
					 * not null, then the array must be null terminated. The argv array only has
 | 
				
			||||||
 | 
					 * to contain the arguments, the executable filename doesn't have to be in
 | 
				
			||||||
 | 
					 * the first element, which is normally the convention.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]   executable     Executable file name.
 | 
				
			||||||
 | 
					 * @param[in]   argv           Arguments array.
 | 
				
			||||||
 | 
					 * @param[out]  pid            ID of the created process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns A dds_retcode_t indicating success or failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OK
 | 
				
			||||||
 | 
					 *             Process successfully created.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
				
			||||||
 | 
					 *             Provided file is not available or not executable.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_NOT_ALLOWED
 | 
				
			||||||
 | 
					 *             Caller is not permitted to start the process.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OUT_OF_RESOURCES
 | 
				
			||||||
 | 
					 *             Not enough resources to start the process.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ERROR
 | 
				
			||||||
 | 
					 *             Process could not be created.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_create(
 | 
				
			||||||
 | 
					  const char *executable,
 | 
				
			||||||
 | 
					  char *const argv[],
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Wait for a specific child process to have finished.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function takes a process id and will wait until the related process
 | 
				
			||||||
 | 
					 * has finished or the timeout is reached.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the process finished, then the exit code of that process will be copied
 | 
				
			||||||
 | 
					 * into the given 'code' argument.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Internally, the timeout can be round-up to the nearest milliseconds or
 | 
				
			||||||
 | 
					 * seconds, depending on the platform.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * See ddsrt_proc_waitpids() for waiting on all child processes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]   pid            Process ID (PID) to get the exit code from.
 | 
				
			||||||
 | 
					 * @param[in]   timemout       Time within the process is expected to finish.
 | 
				
			||||||
 | 
					 * @param[out]  code           The exit code of the process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns A dds_retcode_t indicating success or failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OK
 | 
				
			||||||
 | 
					 *             Process has terminated and its exit code has been captured.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_PRECONDITION_NOT_MET
 | 
				
			||||||
 | 
					 *             Process is still alive (only when timeout == 0).
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_TIMEOUT
 | 
				
			||||||
 | 
					 *             Process is still alive (even after the timeout).
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
				
			||||||
 | 
					 *             Negative timeout.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_NOT_FOUND
 | 
				
			||||||
 | 
					 *             Process unknown.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ERROR
 | 
				
			||||||
 | 
					 *             Getting the exit code failed for an unknown reason.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpid(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid,
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  int32_t *code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Wait for a random child process to have finished.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will wait until anyone of the child processes has
 | 
				
			||||||
 | 
					 * finished or the timeout is reached.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If a process finished, then the exit code of that process will be
 | 
				
			||||||
 | 
					 * copied into the given 'code' argument. The pid of the process will
 | 
				
			||||||
 | 
					 * be put in the 'pid' argument.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Internally, the timeout can be round-up to the nearest milliseconds or
 | 
				
			||||||
 | 
					 * seconds, depending on the platform.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * See ddsrt_proc_waitpid() for waiting on a specific child process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]   timemout       Time within a process is expected to finish.
 | 
				
			||||||
 | 
					 * @param[out]  pid            Process ID (PID) of the finished process.
 | 
				
			||||||
 | 
					 * @param[out]  code           The exit code of the process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns A dds_retcode_t indicating success or failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OK
 | 
				
			||||||
 | 
					 *             A process has terminated.
 | 
				
			||||||
 | 
					 *             Its exit code and pid have been captured.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_PRECONDITION_NOT_MET
 | 
				
			||||||
 | 
					 *             All child processes are still alive (only when timeout == 0).
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_TIMEOUT
 | 
				
			||||||
 | 
					 *             All child processes are still alive (even after the timeout).
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
				
			||||||
 | 
					 *             Negative timeout.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_NOT_FOUND
 | 
				
			||||||
 | 
					 *             There are no processes to wait for.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ERROR
 | 
				
			||||||
 | 
					 *             Getting the exit code failed for an unknown reason.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpids(
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid,
 | 
				
			||||||
 | 
					  int32_t *code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Checks if a process exists.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]   pid            Process ID (PID) to check if it exists.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns A dds_retcode_t indicating success or failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OK
 | 
				
			||||||
 | 
					 *             The process exists.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_NOT_FOUND
 | 
				
			||||||
 | 
					 *             The process does not exist.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ERROR
 | 
				
			||||||
 | 
					 *             Determining if a process exists or not, failed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_exists(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Kill a process.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will try to forcefully kill the process (identified
 | 
				
			||||||
 | 
					 * by pid).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * When DDS_RETCODE_OK is returned, it doesn't mean that the process
 | 
				
			||||||
 | 
					 * was actually killed. It only indicates that the process was
 | 
				
			||||||
 | 
					 * 'told' to terminate. Call ddsrt_proc_exists() to know
 | 
				
			||||||
 | 
					 * for sure if the process was killed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param[in]   pid       Process ID (PID) of the process to terminate.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns A dds_retcode_t indicating success or failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_OK
 | 
				
			||||||
 | 
					 *             Kill attempt has been started.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_BAD_PARAMETER
 | 
				
			||||||
 | 
					 *             Process unknown.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ILLEGAL_OPERATION
 | 
				
			||||||
 | 
					 *             Caller is not allowed to kill the process.
 | 
				
			||||||
 | 
					 * @retval DDS_RETCODE_ERROR
 | 
				
			||||||
 | 
					 *             Kill failed for an unknown reason.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DDS_EXPORT dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_kill(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined (__cplusplus)
 | 
					#if defined (__cplusplus)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,6 @@
 | 
				
			||||||
#include "dds/ddsrt/heap.h"
 | 
					#include "dds/ddsrt/heap.h"
 | 
				
			||||||
#include "dds/ddsrt/log.h"
 | 
					#include "dds/ddsrt/log.h"
 | 
				
			||||||
#include "dds/ddsrt/string.h"
 | 
					#include "dds/ddsrt/string.h"
 | 
				
			||||||
#include "dds/ddsrt/expand_envvars.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef char * (*expand_fn)(const char *src0);
 | 
					typedef char * (*expand_fn)(const char *src0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 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 "dds/ddsrt/process.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if !defined(_WIN32)
 | 
					 | 
				
			||||||
# include <unistd.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ddsrt_pid_t
 | 
					 | 
				
			||||||
ddsrt_getpid(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#if defined(_WIN32)
 | 
					 | 
				
			||||||
    return GetCurrentProcessId();
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    /* Mapped to taskIdSelf() in VxWorks kernel mode. */
 | 
					 | 
				
			||||||
    return getpid();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										309
									
								
								src/ddsrt/src/process/posix/process.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								src/ddsrt/src/process/posix/process.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,309 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include "dds/ddsrt/process.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/string.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/heap.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ddsrt_pid_t
 | 
				
			||||||
 | 
					ddsrt_getpid(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /* Mapped to taskIdSelf() in VxWorks kernel mode. */
 | 
				
			||||||
 | 
					  return getpid();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This'll take a argv and prefixes it with the given prefix.
 | 
				
			||||||
 | 
					 * If argv is NULL, the new argv array will only contain the prefix and a NULL.
 | 
				
			||||||
 | 
					 * The result array is always terminated with NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static char**
 | 
				
			||||||
 | 
					prefix_argv(const char *prefix, char *const argv_in[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char **argv_out;
 | 
				
			||||||
 | 
					  size_t argc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (argv_in != NULL) {
 | 
				
			||||||
 | 
					    while (argv_in[argc] != NULL) {
 | 
				
			||||||
 | 
					      argc++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  argv_out = ddsrt_calloc((argc + 2), sizeof(char*));
 | 
				
			||||||
 | 
					  if (argv_out) {
 | 
				
			||||||
 | 
					    size_t argi;
 | 
				
			||||||
 | 
					    argv_out[0] = (char*)prefix;
 | 
				
			||||||
 | 
					    for (argi = 0; argi < argc; argi++) {
 | 
				
			||||||
 | 
					      argv_out[argi + 1] = (char*)argv_in[argi];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    argv_out[argc + 1] = NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return argv_out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void no_op(int sig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  (void)sig;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static dds_retcode_t
 | 
				
			||||||
 | 
					waitpids(
 | 
				
			||||||
 | 
					  ddsrt_pid_t request_pid,
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  ddsrt_pid_t *child_pid,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  struct sigaction sigactold;
 | 
				
			||||||
 | 
					  struct sigaction sigact;
 | 
				
			||||||
 | 
					  dds_retcode_t rv;
 | 
				
			||||||
 | 
					  int options = 0;
 | 
				
			||||||
 | 
					  int ret;
 | 
				
			||||||
 | 
					  int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout < 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout == 0) {
 | 
				
			||||||
 | 
					    options = WNOHANG;
 | 
				
			||||||
 | 
					  } else if (timeout != DDS_INFINITY) {
 | 
				
			||||||
 | 
					    /* Round-up timemout to alarm seconds. */
 | 
				
			||||||
 | 
					    unsigned secs;
 | 
				
			||||||
 | 
					    secs = (unsigned)(timeout / DDS_NSECS_IN_SEC);
 | 
				
			||||||
 | 
					    if ((timeout % DDS_NSECS_IN_SEC) != 0) {
 | 
				
			||||||
 | 
					      secs++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* Be sure that the SIGALRM only wakes up waitpid. */
 | 
				
			||||||
 | 
					    sigemptyset (&sigact.sa_mask);
 | 
				
			||||||
 | 
					    sigact.sa_handler = no_op;
 | 
				
			||||||
 | 
					    sigact.sa_flags = 0;
 | 
				
			||||||
 | 
					    sigaction (SIGALRM, &sigact, &sigactold);
 | 
				
			||||||
 | 
					    /* Now, set the alarm. */
 | 
				
			||||||
 | 
					    alarm(secs);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = waitpid(request_pid, &s, options);
 | 
				
			||||||
 | 
					  if (ret > 0) {
 | 
				
			||||||
 | 
					    if (code) {
 | 
				
			||||||
 | 
					      if (WIFEXITED(s)) {
 | 
				
			||||||
 | 
					        *code = WEXITSTATUS(s);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        *code = 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (child_pid) {
 | 
				
			||||||
 | 
					      *child_pid = ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  } else if (ret == 0) {
 | 
				
			||||||
 | 
					    /* Process is still alive. */
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
				
			||||||
 | 
					  } else if ((ret == -1) && (errno == EINTR)) {
 | 
				
			||||||
 | 
					    /* Interrupted,
 | 
				
			||||||
 | 
					     * so process(es) likely didn't change state and are/is alive. */
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_TIMEOUT;
 | 
				
			||||||
 | 
					  } else if ((ret == -1) && (errno == ECHILD)) {
 | 
				
			||||||
 | 
					    /* Unknown pid. */
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    /* Unknown error. */
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ((timeout != 0) && (timeout != DDS_INFINITY)) {
 | 
				
			||||||
 | 
					    /* Clean the alarm. */
 | 
				
			||||||
 | 
					    alarm(0);
 | 
				
			||||||
 | 
					    /* Reset SIGALRM actions. */
 | 
				
			||||||
 | 
					    sigaction(SIGALRM, &sigactold, NULL);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_create(
 | 
				
			||||||
 | 
					  const char *executable,
 | 
				
			||||||
 | 
					  char *const argv[],
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv;
 | 
				
			||||||
 | 
					  char **exec_argv;
 | 
				
			||||||
 | 
					  int exec_fds[2];
 | 
				
			||||||
 | 
					  int exec_err;
 | 
				
			||||||
 | 
					  pid_t spawn;
 | 
				
			||||||
 | 
					  ssize_t nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(executable != NULL);
 | 
				
			||||||
 | 
					  assert(pid != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Prefix the argv with the executable, which is the convention. */
 | 
				
			||||||
 | 
					  exec_argv = prefix_argv(executable, argv);
 | 
				
			||||||
 | 
					  if (exec_argv == NULL) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OUT_OF_RESOURCES;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Prepare pipe to know the result of the exec. */
 | 
				
			||||||
 | 
					  if (pipe(exec_fds) == -1) {
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_OUT_OF_RESOURCES;
 | 
				
			||||||
 | 
					    goto fail_pipe;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if ((fcntl(exec_fds[0], F_SETFD, fcntl(exec_fds[0], F_GETFD) | FD_CLOEXEC) == -1) ||
 | 
				
			||||||
 | 
					      (fcntl(exec_fds[1], F_SETFD, fcntl(exec_fds[1], F_GETFD) | FD_CLOEXEC) == -1) ){
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					    goto fail_fctl;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Be sure to not trigger the SIGCHLD. */
 | 
				
			||||||
 | 
					  signal(SIGCHLD, SIG_DFL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Create a new process. */
 | 
				
			||||||
 | 
					  spawn = fork();
 | 
				
			||||||
 | 
					  if (spawn == -1)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					    goto fail_fork;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if (spawn == 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    /* Child process */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Run the executable, replacing current process. */
 | 
				
			||||||
 | 
					    execv(executable, exec_argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If executing this, something has gone wrong */
 | 
				
			||||||
 | 
					    exec_err = errno;
 | 
				
			||||||
 | 
					    if (write(exec_fds[1], &exec_err, sizeof(int)) < (ssize_t)sizeof(int)) {
 | 
				
			||||||
 | 
					      DDS_ERROR("Could not write proc error pipe.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    close(exec_fds[1]);
 | 
				
			||||||
 | 
					    close(exec_fds[0]);
 | 
				
			||||||
 | 
					    ddsrt_free(exec_argv);
 | 
				
			||||||
 | 
					    _exit(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    /* Parent process */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Get execv result. */
 | 
				
			||||||
 | 
					    rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					    close(exec_fds[1]);
 | 
				
			||||||
 | 
					    nr = read(exec_fds[0], &exec_err, sizeof(int));
 | 
				
			||||||
 | 
					    if (nr == 0) {
 | 
				
			||||||
 | 
					      /* Pipe closed by successful execv. */
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					    } else if (nr == sizeof(int)) {
 | 
				
			||||||
 | 
					      /* Translate execv error. */
 | 
				
			||||||
 | 
					      if ((exec_err == ENOENT ) ||
 | 
				
			||||||
 | 
					          (exec_err == ENOEXEC) ){
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					      } else if (exec_err == EACCES) {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_NOT_ALLOWED;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    close(exec_fds[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					      /* Remember child pid. */
 | 
				
			||||||
 | 
					      *pid = spawn;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      /* Remove the failed fork pid from the system list. */
 | 
				
			||||||
 | 
					      waitpid(spawn, NULL, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ddsrt_free(exec_argv);
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail_fork:
 | 
				
			||||||
 | 
					fail_fctl:
 | 
				
			||||||
 | 
					  close(exec_fds[0]);
 | 
				
			||||||
 | 
					  close(exec_fds[1]);
 | 
				
			||||||
 | 
					fail_pipe:
 | 
				
			||||||
 | 
					  ddsrt_free(exec_argv);
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpid(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid,
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (pid > 0) {
 | 
				
			||||||
 | 
					    return waitpids(pid, timeout, NULL, code);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpids(
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return waitpids(0, timeout, pid, code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_exists(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (kill(pid, 0) == 0)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  else if (errno == EPERM)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  else if (errno == ESRCH)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    return DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_kill(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (kill(pid, SIGKILL) == 0)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  else if (errno == EPERM)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_ILLEGAL_OPERATION;
 | 
				
			||||||
 | 
					  else if (errno == ESRCH)
 | 
				
			||||||
 | 
					    return DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    return DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										447
									
								
								src/ddsrt/src/process/windows/process.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								src/ddsrt/src/process/windows/process.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,447 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <process.h>
 | 
				
			||||||
 | 
					#include "dds/ddsrt/heap.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/time.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/string.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/atomics.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/process.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/timeconv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ddsrt_pid_t
 | 
				
			||||||
 | 
					ddsrt_getpid(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return GetCurrentProcessId();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static HANDLE        pid_to_phdl          (ddsrt_pid_t pid);
 | 
				
			||||||
 | 
					static dds_retcode_t process_get_exit_code(HANDLE phdl, int32_t *code);
 | 
				
			||||||
 | 
					static dds_retcode_t process_kill         (HANDLE phdl);
 | 
				
			||||||
 | 
					static char*         commandline          (const char *exe, char *const argv_in[]);
 | 
				
			||||||
 | 
					static BOOL          child_add            (HANDLE phdl);
 | 
				
			||||||
 | 
					static void          child_remove         (HANDLE phdl);
 | 
				
			||||||
 | 
					static DWORD         child_list           (HANDLE *list, DWORD max);
 | 
				
			||||||
 | 
					static HANDLE        child_handle         (ddsrt_pid_t pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_create(
 | 
				
			||||||
 | 
					  const char *executable,
 | 
				
			||||||
 | 
					  char *const argv[],
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					  PROCESS_INFORMATION process_info;
 | 
				
			||||||
 | 
					  STARTUPINFO si;
 | 
				
			||||||
 | 
					  char *cmd;
 | 
				
			||||||
 | 
					  LPTCH environment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(executable != NULL);
 | 
				
			||||||
 | 
					  assert(pid != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cmd = commandline(executable, argv);
 | 
				
			||||||
 | 
					  if (cmd == NULL) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OUT_OF_RESOURCES;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memset(&si, 0, sizeof(STARTUPINFO));
 | 
				
			||||||
 | 
					  si.cb = sizeof(STARTUPINFO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* The new process will inherit the input/output handles. */
 | 
				
			||||||
 | 
					  /* TODO: Redirect is not working yet. */
 | 
				
			||||||
 | 
					  si.dwFlags = STARTF_USESTDHANDLES;
 | 
				
			||||||
 | 
					  si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 | 
				
			||||||
 | 
					  si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
 | 
				
			||||||
 | 
					  si.hStdError  = GetStdHandle(STD_ERROR_HANDLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Get the environment variables to pass along. */
 | 
				
			||||||
 | 
					  environment = GetEnvironmentStrings();
 | 
				
			||||||
 | 
					  if(environment){
 | 
				
			||||||
 | 
					    BOOL created;
 | 
				
			||||||
 | 
					    created = CreateProcess(executable,               // ApplicationName
 | 
				
			||||||
 | 
					                            cmd,                      // CommandLine
 | 
				
			||||||
 | 
					                            NULL,                     // ProcessAttributes
 | 
				
			||||||
 | 
					                            NULL,                     // ThreadAttributes
 | 
				
			||||||
 | 
					                            TRUE,                     // InheritHandles
 | 
				
			||||||
 | 
					                            CREATE_NO_WINDOW,         // dwCreationFlags
 | 
				
			||||||
 | 
					                            (LPVOID)environment,      // Environment
 | 
				
			||||||
 | 
					                            NULL,                     // CurrentDirectory
 | 
				
			||||||
 | 
					                            &si,                      // StartupInfo
 | 
				
			||||||
 | 
					                            &process_info);           // ProcessInformation
 | 
				
			||||||
 | 
					    if (created) {
 | 
				
			||||||
 | 
					      if (child_add(process_info.hProcess)) {
 | 
				
			||||||
 | 
					        *pid = process_info.dwProcessId;
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        process_kill(process_info.hProcess);
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_OUT_OF_RESOURCES;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      DWORD error = GetLastError();
 | 
				
			||||||
 | 
					      if ((ERROR_FILE_NOT_FOUND == error) ||
 | 
				
			||||||
 | 
					          (ERROR_PATH_NOT_FOUND == error)) {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					      } else if (ERROR_ACCESS_DENIED  == error) {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_NOT_ALLOWED;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    FreeEnvironmentStrings(environment);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ddsrt_free(cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpid(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid,
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  HANDLE phdl;
 | 
				
			||||||
 | 
					  DWORD ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout < 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  phdl = child_handle(pid);
 | 
				
			||||||
 | 
					  if (phdl == 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout > 0) {
 | 
				
			||||||
 | 
					    ret = WaitForSingleObject(phdl, ddsrt_duration_to_msecs_ceil(timeout));
 | 
				
			||||||
 | 
					    if (ret != WAIT_OBJECT_0) {
 | 
				
			||||||
 | 
					      if (ret == WAIT_TIMEOUT) {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_TIMEOUT;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    rv = process_get_exit_code(phdl, code);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    child_remove(phdl);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_waitpids(
 | 
				
			||||||
 | 
					  dds_duration_t timeout,
 | 
				
			||||||
 | 
					  ddsrt_pid_t *pid,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  HANDLE hdls[MAXIMUM_WAIT_OBJECTS];
 | 
				
			||||||
 | 
					  HANDLE phdl;
 | 
				
			||||||
 | 
					  DWORD cnt;
 | 
				
			||||||
 | 
					  DWORD ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (timeout < 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cnt = child_list(hdls, MAXIMUM_WAIT_OBJECTS);
 | 
				
			||||||
 | 
					  if (cnt == 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = WaitForMultipleObjects(cnt, hdls, FALSE, ddsrt_duration_to_msecs_ceil(timeout));
 | 
				
			||||||
 | 
					  if ((ret < WAIT_OBJECT_0) || (ret >= (WAIT_OBJECT_0 + cnt))) {
 | 
				
			||||||
 | 
					    if (ret == WAIT_TIMEOUT) {
 | 
				
			||||||
 | 
					      if (timeout == 0) {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        rv = DDS_RETCODE_TIMEOUT;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    /* Get the handle of the specific child that was triggered. */
 | 
				
			||||||
 | 
					    phdl = hdls[ret - WAIT_OBJECT_0];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    rv = process_get_exit_code(phdl, code);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    if (pid) {
 | 
				
			||||||
 | 
					      *pid = GetProcessId(phdl);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    child_remove(phdl);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_exists(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					  HANDLE phdl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  phdl = pid_to_phdl(pid);
 | 
				
			||||||
 | 
					  if (phdl != 0) {
 | 
				
			||||||
 | 
					    rv = process_get_exit_code(phdl, NULL);
 | 
				
			||||||
 | 
					    if (rv == DDS_RETCODE_PRECONDITION_NOT_MET) {
 | 
				
			||||||
 | 
					      /* Process still exists. */
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					    } else if (rv == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					      /* The process has gone. */
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_NOT_FOUND;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CloseHandle(phdl);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dds_retcode_t
 | 
				
			||||||
 | 
					ddsrt_proc_kill(
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_BAD_PARAMETER;
 | 
				
			||||||
 | 
					  HANDLE phdl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  phdl = pid_to_phdl(pid);
 | 
				
			||||||
 | 
					  if (phdl != 0) {
 | 
				
			||||||
 | 
					    /* Forcefully kill. */
 | 
				
			||||||
 | 
					    rv = process_kill(phdl);
 | 
				
			||||||
 | 
					    CloseHandle(phdl);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static HANDLE
 | 
				
			||||||
 | 
					pid_to_phdl(ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static dds_retcode_t
 | 
				
			||||||
 | 
					process_get_exit_code(
 | 
				
			||||||
 | 
					  HANDLE phdl,
 | 
				
			||||||
 | 
					  int32_t *code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rv = DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					  DWORD tr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(phdl != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (GetExitCodeProcess(phdl, &tr)) {
 | 
				
			||||||
 | 
					    if (tr == STILL_ACTIVE) {
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_PRECONDITION_NOT_MET;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      if (code) {
 | 
				
			||||||
 | 
					        *code = (int32_t)tr;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      rv = DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Forcefully kill the given process. */
 | 
				
			||||||
 | 
					static dds_retcode_t
 | 
				
			||||||
 | 
					process_kill(HANDLE phdl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  assert(phdl != 0);
 | 
				
			||||||
 | 
					  if (TerminateProcess(phdl, 1 /* exit code */) != 0) {
 | 
				
			||||||
 | 
					    return DDS_RETCODE_OK;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return DDS_RETCODE_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Add quotes to a given string, escape it and add it to a buffer. */
 | 
				
			||||||
 | 
					static char*
 | 
				
			||||||
 | 
					insert_char(char *buf, size_t *len, size_t *max, char c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  static const size_t buf_inc = 64;
 | 
				
			||||||
 | 
					  if (*len == *max) {
 | 
				
			||||||
 | 
					    *max += buf_inc;
 | 
				
			||||||
 | 
					    buf = ddsrt_realloc(buf, *max);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (buf) {
 | 
				
			||||||
 | 
					    buf[(*len)++] = c;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static char*
 | 
				
			||||||
 | 
					stringify_cat(char *buf, size_t *len, size_t *max, const char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char last = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Start stringification with an opening double-quote. */
 | 
				
			||||||
 | 
					  buf = insert_char(buf, len, max, '\"');
 | 
				
			||||||
 | 
					  if (!buf) goto end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Copy and escape the string. */
 | 
				
			||||||
 | 
					  while ((*str) != '\0') {
 | 
				
			||||||
 | 
					    if (*str == '\"') {
 | 
				
			||||||
 | 
					      buf = insert_char(buf, len, max, '\\');
 | 
				
			||||||
 | 
					      if (!buf) goto end;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    buf = insert_char(buf, len, max, *str);
 | 
				
			||||||
 | 
					    if (!buf) goto end;
 | 
				
			||||||
 | 
					    last = *str;
 | 
				
			||||||
 | 
					    str++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* For some reason, only the last backslash will be stripped.
 | 
				
			||||||
 | 
					   * No need to escape the other backslashes. */
 | 
				
			||||||
 | 
					  if (last == '\\') {
 | 
				
			||||||
 | 
					    buf = insert_char(buf, len, max, '\\');
 | 
				
			||||||
 | 
					    if (!buf) goto end;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* End stringification. */
 | 
				
			||||||
 | 
					  buf = insert_char(buf, len, max, '\"');
 | 
				
			||||||
 | 
					  if (!buf) goto end;
 | 
				
			||||||
 | 
					  buf = insert_char(buf, len, max, ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					  return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Create command line with executable and arguments. */
 | 
				
			||||||
 | 
					static char*
 | 
				
			||||||
 | 
					commandline(const char *exe, char *const argv_in[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *cmd = NULL;
 | 
				
			||||||
 | 
					  size_t len = 0;
 | 
				
			||||||
 | 
					  size_t max = 0;
 | 
				
			||||||
 | 
					  size_t argi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(exe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Add quoted and escaped executable. */
 | 
				
			||||||
 | 
					  cmd = stringify_cat(cmd, &len, &max, exe);
 | 
				
			||||||
 | 
					  if (!cmd) goto end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Add quoted and escaped arguments. */
 | 
				
			||||||
 | 
					  if (argv_in != NULL) {
 | 
				
			||||||
 | 
					    for (argi = 0; argv_in[argi] != NULL; argi++) {
 | 
				
			||||||
 | 
					      cmd = stringify_cat(cmd, &len, &max, argv_in[argi]);
 | 
				
			||||||
 | 
					      if (!cmd) goto end;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Terminate command line string. */
 | 
				
			||||||
 | 
					  cmd = insert_char(cmd, &len, &max, '\0');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
					  return cmd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Maintain a list of children to be able to wait for all them. */
 | 
				
			||||||
 | 
					static ddsrt_atomic_voidp_t g_children[MAXIMUM_WAIT_OBJECTS] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static BOOL
 | 
				
			||||||
 | 
					child_update(HANDLE old, HANDLE new)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  BOOL updated = FALSE;
 | 
				
			||||||
 | 
					  for (int i = 0; (i < MAXIMUM_WAIT_OBJECTS) && (!updated); i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    updated = ddsrt_atomic_casvoidp(&(g_children[i]), old, new);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return updated;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static BOOL
 | 
				
			||||||
 | 
					child_add(HANDLE phdl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return child_update(0, phdl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					child_remove(HANDLE phdl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  (void)child_update(phdl, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DWORD
 | 
				
			||||||
 | 
					child_list(HANDLE *list, DWORD max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  HANDLE hdl;
 | 
				
			||||||
 | 
					  int cnt = 0;
 | 
				
			||||||
 | 
					  assert(list);
 | 
				
			||||||
 | 
					  assert(max <= MAXIMUM_WAIT_OBJECTS);
 | 
				
			||||||
 | 
					  for (int i = 0; (i < MAXIMUM_WAIT_OBJECTS); i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    hdl = ddsrt_atomic_ldvoidp(&(g_children[i]));
 | 
				
			||||||
 | 
					    if (hdl != 0) {
 | 
				
			||||||
 | 
					      list[cnt++] = hdl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static HANDLE
 | 
				
			||||||
 | 
					child_handle(ddsrt_pid_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  HANDLE phdl = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (int i = 0; (i < MAXIMUM_WAIT_OBJECTS) && (phdl == 0); i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    phdl = ddsrt_atomic_ldvoidp(&(g_children[i]));
 | 
				
			||||||
 | 
					    if (phdl != 0) {
 | 
				
			||||||
 | 
					      if (GetProcessId(phdl) != pid) {
 | 
				
			||||||
 | 
					        phdl = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return phdl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ set(sources
 | 
				
			||||||
    "random.c"
 | 
					    "random.c"
 | 
				
			||||||
    "strlcpy.c"
 | 
					    "strlcpy.c"
 | 
				
			||||||
    "socket.c"
 | 
					    "socket.c"
 | 
				
			||||||
 | 
					    "process.c"
 | 
				
			||||||
    "select.c")
 | 
					    "select.c")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_cunit_executable(cunit_ddsrt ${sources})
 | 
					add_cunit_executable(cunit_ddsrt ${sources})
 | 
				
			||||||
| 
						 | 
					@ -42,3 +43,26 @@ endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_include_directories(
 | 
					target_include_directories(
 | 
				
			||||||
  cunit_ddsrt PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
 | 
					  cunit_ddsrt PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create a separate test application that will be used to
 | 
				
			||||||
 | 
					# test process management.
 | 
				
			||||||
 | 
					add_executable(process_app process_app.c)
 | 
				
			||||||
 | 
					target_link_libraries(process_app PRIVATE ddsrt)
 | 
				
			||||||
 | 
					target_include_directories(
 | 
				
			||||||
 | 
					        process_app
 | 
				
			||||||
 | 
					        PRIVATE
 | 
				
			||||||
 | 
					        "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
 | 
				
			||||||
 | 
					# Force the app to be at the same location, no matter what platform or build type.
 | 
				
			||||||
 | 
					set_target_properties(
 | 
				
			||||||
 | 
					        process_app
 | 
				
			||||||
 | 
					        PROPERTIES
 | 
				
			||||||
 | 
					        RUNTIME_OUTPUT_DIRECTORY                ${CMAKE_CURRENT_BINARY_DIR}
 | 
				
			||||||
 | 
					        RUNTIME_OUTPUT_DIRECTORY_DEBUG          ${CMAKE_CURRENT_BINARY_DIR}
 | 
				
			||||||
 | 
					        RUNTIME_OUTPUT_DIRECTORY_RELEASE        ${CMAKE_CURRENT_BINARY_DIR}
 | 
				
			||||||
 | 
					        RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR}
 | 
				
			||||||
 | 
					        RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL     ${CMAKE_CURRENT_BINARY_DIR} )
 | 
				
			||||||
 | 
					# Let the cunit application know the location and name of the test application.
 | 
				
			||||||
 | 
					set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}")
 | 
				
			||||||
 | 
					configure_file(
 | 
				
			||||||
 | 
					        "process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#include "CUnit/Theory.h"
 | 
					#include "CUnit/Theory.h"
 | 
				
			||||||
#include "dds/ddsrt/environ.h"
 | 
					#include "dds/ddsrt/environ.h"
 | 
				
			||||||
#include "dds/ddsrt/misc.h"
 | 
					#include "dds/ddsrt/misc.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/heap.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CU_TheoryDataPoints(ddsrt_environ, bad_name) = {
 | 
					CU_TheoryDataPoints(ddsrt_environ, bad_name) = {
 | 
				
			||||||
  CU_DataPoints(const char *, "", "foo=")
 | 
					  CU_DataPoints(const char *, "", "foo=")
 | 
				
			||||||
| 
						 | 
					@ -91,8 +92,110 @@ CU_Test(ddsrt_environ, getenv)
 | 
				
			||||||
    CU_ASSERT_STRING_EQUAL(ptr, "bar");
 | 
					    CU_ASSERT_STRING_EQUAL(ptr, "bar");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Ensure environement is as it was. */
 | 
					  /* Ensure environment is as it was. */
 | 
				
			||||||
  rc = ddsrt_unsetenv(name);
 | 
					  rc = ddsrt_unsetenv(name);
 | 
				
			||||||
  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
					  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CU_TheoryDataPoints(ddsrt_environ, expand) = {
 | 
				
			||||||
 | 
					  CU_DataPoints(const char *,
 | 
				
			||||||
 | 
					         "${X}",        "$X",          "X",       "${Y}",     "${Q}",      "${X",
 | 
				
			||||||
 | 
					    "${X:-ALT}", "${Q:-ALT}", "${X:-${Y}}", "${Q:-${Y}}", "${X:-$Y}", "${Q:-$Y}", "${X:-}", "${Q:-}",
 | 
				
			||||||
 | 
					    "${X:+SET}", "${Q:+SET}", "${X:+${Y}}", "${Q:+${Y}}", "${X:+$Y}", "${Q:+$Y}", "${X:+}", "${Q:+}",
 | 
				
			||||||
 | 
					    "${X:?SET}", "${Q:?SET}", "${X:?${Y}}", "${Q:?${Y}}", "${X:?$Y}", "${Q:?$Y}", "${X:?}", "${Q:?}"),
 | 
				
			||||||
 | 
					  CU_DataPoints(const char *,
 | 
				
			||||||
 | 
					         "TEST",        "$X",          "X",        "FOO",         "",       NULL,
 | 
				
			||||||
 | 
					         "TEST",       "ALT",       "TEST",        "FOO",     "TEST",       "$Y",   "TEST",       "",
 | 
				
			||||||
 | 
					          "SET",          "",        "FOO",           "",       "$Y",         "",       "",       "",
 | 
				
			||||||
 | 
					         "TEST",        NULL,       "TEST",         NULL,     "TEST",       NULL,   "TEST",     NULL)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					CU_Theory((const char *var, const char *expect), ddsrt_environ, expand)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rc;
 | 
				
			||||||
 | 
					  static const char x_name[]  = "X";
 | 
				
			||||||
 | 
					  static const char x_value[] = "TEST";
 | 
				
			||||||
 | 
					  static const char y_name[]  = "Y";
 | 
				
			||||||
 | 
					  static const char y_value[] = "FOO";
 | 
				
			||||||
 | 
					  char *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Ensure that the vars are not used yet. */
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(x_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(y_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Set the env vars to check expansion. */
 | 
				
			||||||
 | 
					  rc = ddsrt_setenv(x_name, x_value);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_setenv(y_name, y_value);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Expand a string with available environment variables. */
 | 
				
			||||||
 | 
					  ptr = ddsrt_expand_envvars(var);
 | 
				
			||||||
 | 
					  if (ptr) {
 | 
				
			||||||
 | 
					    /* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
 | 
				
			||||||
 | 
					    CU_ASSERT_STRING_EQUAL(ptr, expect);
 | 
				
			||||||
 | 
					    ddsrt_free(ptr);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    /* printf("==== %10s: expand(<null>), expect(<null>))\n", var ? var : "<null>"); */
 | 
				
			||||||
 | 
					    CU_ASSERT_PTR_NULL(expect);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Ensure to reset the environment is as it was. */
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(y_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(x_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CU_TheoryDataPoints(ddsrt_environ, expand_sh) = {
 | 
				
			||||||
 | 
					  CU_DataPoints(const char *,
 | 
				
			||||||
 | 
					         "${X}",        "$X",          "X",       "${Y}",     "${Q}",      "${X",
 | 
				
			||||||
 | 
					    "${X:-ALT}", "${Q:-ALT}", "${X:-${Y}}", "${Q:-${Y}}", "${X:-$Y}", "${Q:-$Y}", "${X:-}", "${Q:-}",
 | 
				
			||||||
 | 
					    "${X:+SET}", "${Q:+SET}", "${X:+${Y}}", "${Q:+${Y}}", "${X:+$Y}", "${Q:+$Y}", "${X:+}", "${Q:+}",
 | 
				
			||||||
 | 
					    "${X:?SET}", "${Q:?SET}", "${X:?${Y}}", "${Q:?${Y}}", "${X:?$Y}", "${Q:?$Y}", "${X:?}", "${Q:?}"),
 | 
				
			||||||
 | 
					  CU_DataPoints(const char *,
 | 
				
			||||||
 | 
					         "TEST",      "TEST",          "X",        "FOO",         "",       NULL,
 | 
				
			||||||
 | 
					         "TEST",       "ALT",       "TEST",        "FOO",     "TEST",      "FOO",   "TEST",       "",
 | 
				
			||||||
 | 
					          "SET",          "",        "FOO",           "",      "FOO",         "",       "",       "",
 | 
				
			||||||
 | 
					         "TEST",        NULL,       "TEST",         NULL,     "TEST",       NULL,   "TEST",     NULL)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t rc;
 | 
				
			||||||
 | 
					  static const char x_name[]  = "X";
 | 
				
			||||||
 | 
					  static const char x_value[] = "TEST";
 | 
				
			||||||
 | 
					  static const char y_name[]  = "Y";
 | 
				
			||||||
 | 
					  static const char y_value[] = "FOO";
 | 
				
			||||||
 | 
					  char *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Ensure that the vars are not used yet. */
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(x_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(y_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Set the env vars to check expansion. */
 | 
				
			||||||
 | 
					  rc = ddsrt_setenv(x_name, x_value);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_setenv(y_name, y_value);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Expand a string with available environment variables. */
 | 
				
			||||||
 | 
					  ptr = ddsrt_expand_envvars_sh(var);
 | 
				
			||||||
 | 
					  if (ptr) {
 | 
				
			||||||
 | 
					    /* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
 | 
				
			||||||
 | 
					    CU_ASSERT_STRING_EQUAL(ptr, expect);
 | 
				
			||||||
 | 
					    ddsrt_free(ptr);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    /* printf("==== %10s: expand(<null>), expect(<null>))\n", var ? var : "<null>"); */
 | 
				
			||||||
 | 
					    CU_ASSERT_PTR_NULL(expect);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Ensure to reset the environment is as it was. */
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(y_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  rc = ddsrt_unsetenv(x_name);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										284
									
								
								src/ddsrt/tests/process.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								src/ddsrt/tests/process.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,284 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright(c) 2019 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include "CUnit/Test.h"
 | 
				
			||||||
 | 
					#include "process_test.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/time.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/strtol.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/environ.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/process.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a process that is expected to exit quickly.
 | 
				
			||||||
 | 
					 * Compare the exit code with the expected exit code.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void create_and_test_exit(const char *arg, int code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					  int32_t status;
 | 
				
			||||||
 | 
					  char *argv[] = { NULL, NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  argv[0] = (char*)arg;
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, DDS_SECS(10), &status);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Check result. */
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(status, code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Garbage collection when needed. */
 | 
				
			||||||
 | 
					  if (ret != DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Try to create a process without arguments.
 | 
				
			||||||
 | 
					 * The exit status of the process should be PROCESS_DONE_NOTHING_EXIT_CODE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, create)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  create_and_test_exit(NULL, TEST_CREATE_EXIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a process that'll sleep for a while.
 | 
				
			||||||
 | 
					 * Try to kill that process.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, kill)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Sleep for 20 seconds. It should be killed before then. */
 | 
				
			||||||
 | 
					  char *argv[] = { TEST_SLEEP_ARG, "20", NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  CU_ASSERT_NOT_EQUAL_FATAL(pid, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Check if process is running. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_exists(pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Kill it. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Check if process is actually gone. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, DDS_SECS(10), NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_exists(pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_NOT_FOUND);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a process that'll return it's own pid value (reduced
 | 
				
			||||||
 | 
					 * to fit the exit code range). It should match the pid that was
 | 
				
			||||||
 | 
					 * returned by the process create (also reduced to be able to
 | 
				
			||||||
 | 
					 * match the returned semi-pid value).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					  int32_t status;
 | 
				
			||||||
 | 
					  char *argv[] = { TEST_PID_ARG, NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  CU_ASSERT_NOT_EQUAL_FATAL(pid, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, DDS_SECS(10), &status);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Compare the pid values. */
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(status, TEST_PID_EXIT(pid));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Garbage collection when needed. */
 | 
				
			||||||
 | 
					  if (ret != DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Set a environment variable in the parent process.
 | 
				
			||||||
 | 
					 * Create a process that should have access to that env var.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_setenv(TEST_ENV_VAR_NAME, TEST_ENV_VAR_VALUE);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  create_and_test_exit(TEST_ENV_ARG, TEST_ENV_EXIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Try to create a process with an non-existing executable file.
 | 
				
			||||||
 | 
					 * It should fail.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, invalid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create("ProbablyNotAnValidExecutable", NULL, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Garbage collection when needed. */
 | 
				
			||||||
 | 
					  if (ret == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a process with a backslash in the argument
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, arg_bslash)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  create_and_test_exit(TEST_BSLASH_ARG, TEST_BSLASH_EXIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a process with a double-quote in the argument
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, arg_dquote)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  create_and_test_exit(TEST_DQUOTE_ARG, TEST_DQUOTE_EXIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create two processes and wait for them simultaneously.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, waitpids)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t child;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid1 = 0;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid2 = 0;
 | 
				
			||||||
 | 
					  int32_t status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Use retpid option to identify return values. */
 | 
				
			||||||
 | 
					  char *argv[] = { TEST_PID_ARG, NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Start two processes. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid1);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid2);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Wait for both processes to have finished. */
 | 
				
			||||||
 | 
					  while (((pid1 != 0) || (pid2 != 0)) && (ret == DDS_RETCODE_OK)) {
 | 
				
			||||||
 | 
					    ret = ddsrt_proc_waitpids(DDS_SECS(10), &child, &status);
 | 
				
			||||||
 | 
					    CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					    if (child == pid1) {
 | 
				
			||||||
 | 
					      CU_ASSERT_EQUAL(status, TEST_PID_EXIT(pid1));
 | 
				
			||||||
 | 
					      pid1 = 0;
 | 
				
			||||||
 | 
					    } else if (child == pid2) {
 | 
				
			||||||
 | 
					      CU_ASSERT_EQUAL(status, TEST_PID_EXIT(pid2));
 | 
				
			||||||
 | 
					      pid2 = 0;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      CU_ASSERT(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpids(DDS_SECS(10), &child, &status);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_NOT_FOUND);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Garbage collection when needed. */
 | 
				
			||||||
 | 
					  if (pid1 != 0) {
 | 
				
			||||||
 | 
					    ddsrt_proc_kill(pid1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (pid2 != 0) {
 | 
				
			||||||
 | 
					    ddsrt_proc_kill(pid2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a sleeping process. Waiting for it should timeout.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, waitpid_timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Sleep for 20 seconds. We should have a timeout before then. */
 | 
				
			||||||
 | 
					  char *argv[] = { TEST_SLEEP_ARG, "20", NULL };
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  CU_ASSERT_NOT_EQUAL_FATAL(pid, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Timeout 0 should return DDS_RETCODE_PRECONDITION_NOT_MET when alive. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, 0, NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, DDS_SECS(1), NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Kill it. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* When killed, DDS_RETCODE_OK should be returned. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpid(pid, DDS_SECS(10), NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a sleeping process. Waiting for it should timeout.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CU_Test(ddsrt_process, waitpids_timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  dds_retcode_t ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Sleep for 20 seconds. We should have a timeout before then. */
 | 
				
			||||||
 | 
					  char *argv[] = { TEST_SLEEP_ARG, "20", NULL };
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_create(TEST_APPLICATION, argv, &pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					  CU_ASSERT_NOT_EQUAL_FATAL(pid, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Timeout 0 should return DDS_RETCODE_PRECONDITION_NOT_MET when alive. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpids(0, NULL, NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpids(DDS_SECS(1), NULL, NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Kill it. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_kill(pid);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* When killed, DDS_RETCODE_OK should be returned. */
 | 
				
			||||||
 | 
					  ret = ddsrt_proc_waitpids(DDS_SECS(10), NULL, NULL);
 | 
				
			||||||
 | 
					  CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										108
									
								
								src/ddsrt/tests/process_app.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/ddsrt/tests/process_app.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,108 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright(c) 2019 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include "process_test.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/strtol.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/environ.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/process.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_create(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  printf(" Process: created without args.\n");
 | 
				
			||||||
 | 
					  return TEST_CREATE_EXIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_sleep(int argi, int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  argi++;
 | 
				
			||||||
 | 
					  if (argi < argc) {
 | 
				
			||||||
 | 
					    long long dorment;
 | 
				
			||||||
 | 
					    ddsrt_strtoll(argv[argi], NULL, 0, &dorment);
 | 
				
			||||||
 | 
					    printf(" Process: sleep %d seconds.\n", (int)dorment);
 | 
				
			||||||
 | 
					    dds_sleepfor(DDS_SECS((int64_t)dorment));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    printf(" Process: no --sleep value.\n");
 | 
				
			||||||
 | 
					    return TEST_EXIT_WRONG_ARGS;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /* Expected to be destroyed before reaching this. */
 | 
				
			||||||
 | 
					  return TEST_EXIT_FAILURE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_pid(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int ret;
 | 
				
			||||||
 | 
					  ddsrt_pid_t pid;
 | 
				
			||||||
 | 
					  pid = ddsrt_getpid();
 | 
				
			||||||
 | 
					  ret = TEST_PID_EXIT(pid);
 | 
				
			||||||
 | 
					  printf(" Process: pid %d reduced to %d exit code.\n", (int)pid, ret);
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_env(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int ret = TEST_EXIT_FAILURE;
 | 
				
			||||||
 | 
					  char *envptr = NULL;
 | 
				
			||||||
 | 
					  if (ddsrt_getenv(TEST_ENV_VAR_NAME, &envptr) == DDS_RETCODE_OK) {
 | 
				
			||||||
 | 
					    printf(" Process: env %s=%s.\n", TEST_ENV_VAR_NAME, envptr);
 | 
				
			||||||
 | 
					    if (strcmp(envptr, TEST_ENV_VAR_VALUE) == 0) {
 | 
				
			||||||
 | 
					      ret = TEST_ENV_EXIT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    printf(" Process: failed to get environment variable.\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_bslash(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  printf(" Process: backslash argument.\n");
 | 
				
			||||||
 | 
					  return TEST_BSLASH_EXIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int test_dquote(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  printf(" Process: double-quote argument.\n");
 | 
				
			||||||
 | 
					  return TEST_DQUOTE_EXIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The spawned application used in the process tests.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (argc == 1) {
 | 
				
			||||||
 | 
					    ret = test_create();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    if (strcmp(argv[1], TEST_SLEEP_ARG) == 0) {
 | 
				
			||||||
 | 
					      ret = test_sleep(1, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], TEST_PID_ARG) == 0) {
 | 
				
			||||||
 | 
					      ret = test_pid();
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], TEST_ENV_ARG) == 0) {
 | 
				
			||||||
 | 
					      ret = test_env();
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], TEST_BSLASH_ARG) == 0) {
 | 
				
			||||||
 | 
					      ret = test_bslash();
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], TEST_DQUOTE_ARG) == 0) {
 | 
				
			||||||
 | 
					      ret = test_dquote();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      printf(" Process: unknown argument.\n");
 | 
				
			||||||
 | 
					      ret = TEST_EXIT_WRONG_ARGS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/ddsrt/tests/process_test.h.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/ddsrt/tests/process_test.h.in
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 DDSRT_TEST_PROCESS_TEST_H
 | 
				
			||||||
 | 
					#define DDSRT_TEST_PROCESS_TEST_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the application name from cmake to automatically
 | 
				
			||||||
 | 
					 * get the proper extension and location. */
 | 
				
			||||||
 | 
					#define TEST_APPLICATION "@process_app_name@"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_SLEEP_ARG        "--sleep"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_EXIT_GENERIC_OK  (0)
 | 
				
			||||||
 | 
					#define TEST_EXIT_FAILURE     (1)
 | 
				
			||||||
 | 
					#define TEST_EXIT_WRONG_ARGS  (2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_CREATE_ARG       NULL
 | 
				
			||||||
 | 
					#define TEST_CREATE_EXIT      (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_PID_ARG          "--retpid"
 | 
				
			||||||
 | 
					#define TEST_PID_EXIT(pid)    ((int)(int32_t)(pid % 127))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_ENV_ARG          "--checkenv"
 | 
				
			||||||
 | 
					#define TEST_ENV_EXIT         (12)
 | 
				
			||||||
 | 
					#define TEST_ENV_VAR_NAME     "TEST_ENV_VAR_NAME"
 | 
				
			||||||
 | 
					#define TEST_ENV_VAR_VALUE    "TEST_ENV_VAR_VALUE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_BSLASH_ARG       "\\left\\\\right\\"
 | 
				
			||||||
 | 
					#define TEST_BSLASH_EXIT      (int)('\\')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_DQUOTE_ARG       "\"left\"\"right\""
 | 
				
			||||||
 | 
					#define TEST_DQUOTE_EXIT      (int)('"')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* DDSRT_TEST_PROCESS_TEST_H */
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/mpt/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/mpt/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					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}")
 | 
				
			||||||
 | 
					set(MPT_DEFAULT_TIMEOUT "60")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_subdirectory(mpt)
 | 
				
			||||||
 | 
					add_subdirectory(tests)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/mpt/mpt/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/mpt/mpt/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										173
									
								
								src/mpt/mpt/cmake/MPT.cmake
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/mpt/mpt/cmake/MPT.cmake
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,173 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 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} "${MPT_DEFAULT_TIMEOUT}" 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:
 | 
				
			||||||
 | 
					  #  - <word> <word>
 | 
				
			||||||
 | 
					  #  - <word> *<word>
 | 
				
			||||||
 | 
					  #  - <word>* <word> *<word>
 | 
				
			||||||
 | 
					  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)
 | 
				
			||||||
 | 
					endfunction()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										157
									
								
								src/mpt/mpt/include/mpt/mpt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/mpt/mpt/include/mpt/mpt.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,157 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#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 */
 | 
				
			||||||
							
								
								
									
										153
									
								
								src/mpt/mpt/include/mpt/private/mpt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/mpt/mpt/include/mpt/private/mpt.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 */
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/mpt/mpt/include/mpt/resource.h.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/mpt/mpt/include/mpt/resource.h.in
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#ifndef MPT_RESOURCE_H_INCLUDED
 | 
				
			||||||
 | 
					#define MPT_RESOURCE_H_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MPT_SOURCE_ROOT_DIR "@MPT_SOURCE_ROOT_DIR@"
 | 
				
			||||||
 | 
					#define MPT_DEFAULT_TIMEOUT (@MPT_DEFAULT_TIMEOUT@) /* Seconds. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MPT_RESOURCE_H_INCLUDED */
 | 
				
			||||||
							
								
								
									
										549
									
								
								src/mpt/mpt/src/main.c.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										549
									
								
								src/mpt/mpt/src/main.c.in
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,549 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include "mpt/mpt.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/heap.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/process.h"
 | 
				
			||||||
 | 
					#include "dds/ddsrt/environ.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _WIN32
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#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 = ddsrt_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) {
 | 
				
			||||||
 | 
					    secs = MPT_DEFAULT_TIMEOUT;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  test->timeout = DDS_SECS(secs + 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/mpt/tests/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/mpt/tests/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/mpt/tests/basic/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/mpt/tests/basic/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/mpt/tests/basic/etc/config_any.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/mpt/tests/basic/etc/config_any.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<CycloneDDS>
 | 
				
			||||||
 | 
					  <Domain>
 | 
				
			||||||
 | 
					    <Id>any</Id>
 | 
				
			||||||
 | 
					  </Domain>
 | 
				
			||||||
 | 
					  <DDSI2E>
 | 
				
			||||||
 | 
					    <General>
 | 
				
			||||||
 | 
					      <NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
 | 
				
			||||||
 | 
					      <AllowMulticast>true</AllowMulticast>
 | 
				
			||||||
 | 
					      <EnableMulticastLoopback>true</EnableMulticastLoopback>
 | 
				
			||||||
 | 
					    </General>
 | 
				
			||||||
 | 
					    <Compatibility>
 | 
				
			||||||
 | 
					      <StandardsConformance>lax</StandardsConformance>
 | 
				
			||||||
 | 
					    </Compatibility>
 | 
				
			||||||
 | 
					    <!--Tracing>
 | 
				
			||||||
 | 
					      <Verbosity>finest</Verbosity>
 | 
				
			||||||
 | 
					      <OutputFile>ddsi_${MPT_PROCESS_NAME}.log</OutputFile>
 | 
				
			||||||
 | 
					    </Tracing-->
 | 
				
			||||||
 | 
					  </DDSI2E>
 | 
				
			||||||
 | 
					</CycloneDDS>
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/mpt/tests/basic/etc/config_specific.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/mpt/tests/basic/etc/config_specific.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<CycloneDDS>
 | 
				
			||||||
 | 
					  <Domain>
 | 
				
			||||||
 | 
					    <Id>${DOMAIN_ID}</Id>
 | 
				
			||||||
 | 
					  </Domain>
 | 
				
			||||||
 | 
					  <DDSI2E>
 | 
				
			||||||
 | 
					    <General>
 | 
				
			||||||
 | 
					      <NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
 | 
				
			||||||
 | 
					      <AllowMulticast>true</AllowMulticast>
 | 
				
			||||||
 | 
					      <EnableMulticastLoopback>true</EnableMulticastLoopback>
 | 
				
			||||||
 | 
					    </General>
 | 
				
			||||||
 | 
					    <Compatibility>
 | 
				
			||||||
 | 
					      <StandardsConformance>lax</StandardsConformance>
 | 
				
			||||||
 | 
					    </Compatibility>
 | 
				
			||||||
 | 
					    <!--Tracing>
 | 
				
			||||||
 | 
					      <Verbosity>finest</Verbosity>
 | 
				
			||||||
 | 
					      <OutputFile>ddsi_${MPT_PROCESS_NAME}.log</OutputFile>
 | 
				
			||||||
 | 
					    </Tracing-->
 | 
				
			||||||
 | 
					  </DDSI2E>
 | 
				
			||||||
 | 
					</CycloneDDS>
 | 
				
			||||||
							
								
								
									
										63
									
								
								src/mpt/tests/basic/helloworld.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/mpt/tests/basic/helloworld.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								src/mpt/tests/basic/multi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/mpt/tests/basic/multi.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										239
									
								
								src/mpt/tests/basic/procs/hello.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/mpt/tests/basic/procs/hello.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,239 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								src/mpt/tests/basic/procs/hello.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/mpt/tests/basic/procs/hello.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 */
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/mpt/tests/basic/procs/helloworlddata.idl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/mpt/tests/basic/procs/helloworlddata.idl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					module HelloWorldData
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  struct Msg
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    long userID;
 | 
				
			||||||
 | 
					    string message;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  #pragma keylist Msg userID
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/mpt/tests/self/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/mpt/tests/self/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										711
									
								
								src/mpt/tests/self/asserts.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										711
									
								
								src/mpt/tests/self/asserts.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,711 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#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 : "<null>",
 | 
				
			||||||
 | 
					                    val2 ? val2 : "<null>",
 | 
				
			||||||
 | 
					                    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 : "<null>",
 | 
				
			||||||
 | 
					                     val2 ? val2 : "<null>",
 | 
				
			||||||
 | 
					                     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 : "<null>",
 | 
				
			||||||
 | 
					                       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 : "<null>",
 | 
				
			||||||
 | 
					                           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 : "<null>",
 | 
				
			||||||
 | 
					                          val2 ? val2 : "<null>",
 | 
				
			||||||
 | 
					                          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 : "<null>",
 | 
				
			||||||
 | 
					                           val2 ? val2 : "<null>",
 | 
				
			||||||
 | 
					                           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 : "<null>",
 | 
				
			||||||
 | 
					                             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 : "<null>",
 | 
				
			||||||
 | 
					                                 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										96
									
								
								src/mpt/tests/self/environments.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/mpt/tests/self/environments.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/mpt/tests/self/etc/file
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/mpt/tests/self/etc/file
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										75
									
								
								src/mpt/tests/self/fixtures.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/mpt/tests/self/fixtures.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,75 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MPT_TestProcess(timeout, default_timeout, id, proc_sleep, MPT_ArgValues(DDS_SECS(120)));
 | 
				
			||||||
 | 
					MPT_Test(timeout, default_timeout);
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/mpt/tests/self/ipc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/mpt/tests/self/ipc.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/mpt/tests/self/resources.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/mpt/tests/self/resources.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										186
									
								
								src/mpt/tests/self/usage.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								src/mpt/tests/self/usage.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,186 @@
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue