fork download
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <signal.h>
  8. #include <execinfo.h>
  9. #include <stdlib.h>
  10.  
  11. //-----------------------------------------------------------------------------------------------//
  12. // Macros and forward declarations
  13. //-----------------------------------------------------------------------------------------------//
  14. // Assert macro for tests
  15. #define TESTASSERT(cond) \
  16. do { \
  17. if (!(cond)) { \
  18. assertHandler(__FILE__, __LINE__, #cond); \
  19. } \
  20. } while (0);
  21.  
  22. // Macro to register a test function
  23. #define TEST(name) \
  24. static void name(); \
  25. static TestRef s_Test_ ## name(#name, __FILE__, __LINE__, name); \
  26. static void name()
  27.  
  28. // Forward declarations
  29. class TestRef;
  30. bool runTest(TestRef * test);
  31. void registerTest(TestRef * test);
  32. void crashHandler(int sig);
  33. void assertHandler(const char * file, int line, const char * message);
  34.  
  35.  
  36. //-----------------------------------------------------------------------------------------------//
  37. // Class for storing reference details for a test function
  38. // Test references are stored in a simple linked list
  39. //-----------------------------------------------------------------------------------------------//
  40. // Type def for test function pointer
  41. typedef void (*pfnTestFunc)(void);
  42.  
  43. // Class to store test refence data
  44. class TestRef
  45. {
  46. public:
  47. TestRef(const char * testName, const char * filename, int lineNumber, pfnTestFunc func)
  48. {
  49. function = func;
  50. name = testName;
  51. module = filename;
  52. line = lineNumber;
  53. next = NULL;
  54.  
  55. // Register this test function to be run by the main process
  56. registerTest(this);
  57. }
  58.  
  59. pfnTestFunc function; // Pointer to test function
  60. const char * name; // Test name
  61. const char * module; // Module name
  62. int line; // Module line number
  63. TestRef * next; // Pointer to next test reference in the linked list
  64. };
  65.  
  66. // Linked list to store test references
  67. static TestRef * s_FirstTest = NULL;
  68. static TestRef * s_LastTest = NULL;
  69.  
  70.  
  71. //-----------------------------------------------------------------------------------------------//
  72. // Test functions
  73. //-----------------------------------------------------------------------------------------------//
  74. TEST(TestPass1)
  75. {
  76. int x = 1;
  77. int y = 2;
  78. int z = x + y;
  79. TESTASSERT(z == 3);
  80. }
  81.  
  82. TEST(TestPass2)
  83. {
  84. TESTASSERT(strcmp("abc", "abc") == 0);
  85. }
  86.  
  87. TEST(TestAssertFailed)
  88. {
  89. TESTASSERT(1 == false);
  90. }
  91.  
  92. TEST(TestSegFault)
  93. {
  94. TestRef * p = NULL;
  95. p->function();
  96. }
  97.  
  98.  
  99. //-----------------------------------------------------------------------------------------------//
  100. // Main test runner
  101. //-----------------------------------------------------------------------------------------------//
  102. int main(int argc, char** argv)
  103. {
  104. // Register crash handlers
  105. signal(SIGFPE, crashHandler);
  106. signal(SIGILL, crashHandler);
  107. signal(SIGSEGV, crashHandler);
  108.  
  109. fprintf(stdout, "Running tests...\n");
  110.  
  111. int testCount = 0;
  112. int testPasses = 0;
  113.  
  114. // Loop round all the tests in the linked list
  115. TestRef * test = s_FirstTest;
  116. while (test != NULL)
  117. {
  118. // Print out the name of the test we're about to run
  119. fprintf(stdout, "%s:%s... ", test->module, test->name);
  120. fflush(stdout);
  121.  
  122. testCount++;
  123.  
  124. bool passed = runTest(test);
  125. if (passed == true)
  126. {
  127. testPasses++;
  128. fprintf(stdout, "Ok\n");
  129. }
  130. else
  131. {
  132. fprintf(stdout, "FAILED\n");
  133. }
  134.  
  135. // Get the next test and loop again
  136. test = test->next;
  137. }
  138.  
  139. // Print out final report
  140. int exitCode;
  141. if (testPasses == testCount)
  142. {
  143. fprintf(stdout, "\n*** TEST SUCCESS ***\n");
  144. exitCode = 0;
  145. }
  146. else
  147. {
  148. fprintf(stdout, "\n*** TEST FAILED ***\n");
  149. exitCode = 1;
  150. }
  151. fprintf(stdout, "%d/%d Tests Passed\n", testPasses, testCount);
  152.  
  153. return exitCode;
  154. }
  155.  
  156. // Wrapper function to run the test in a child process
  157. bool runTest(TestRef * test)
  158. {
  159. // Fork the process, the test will actually be run by the child process
  160. pid_t pid = fork();
  161.  
  162. switch (pid)
  163. {
  164. case -1:
  165. fprintf(stderr, "Failed to spawn child process, %d\n", errno);
  166. exit(1); // No point running any further tests
  167.  
  168. case 0:
  169. // We're in the child process so run the test
  170. test->function();
  171. exit(0); // Test passed, so exit the child with a success code
  172.  
  173. default:{
  174. // Parent process, wait for the child to exit
  175. int stat_val;
  176. pid_t child_pid = wait(&stat_val);
  177.  
  178. if (WIFEXITED(stat_val))
  179. {
  180. // Child exited normally so check the return code
  181. if (WEXITSTATUS(stat_val) == 0)
  182. {
  183. // Test passed
  184. return true;
  185. }
  186. else
  187. {
  188. // Test failed
  189. return false;
  190. }
  191. }
  192. else
  193. {
  194. // Child process crashed in a way we couldn't handle!
  195. fprintf(stdout, "Child exited abnormally!\n");
  196. return false;
  197. }
  198.  
  199. break;}
  200. }
  201. }
  202.  
  203. //-----------------------------------------------------------------------------------------------//
  204. // Support functions
  205. //-----------------------------------------------------------------------------------------------//
  206. // Add a new test to the linked list
  207. void registerTest(TestRef * test)
  208. {
  209. if (s_FirstTest == NULL)
  210. {
  211. s_FirstTest = test;
  212. s_LastTest = test;
  213. }
  214. else
  215. {
  216. s_LastTest->next = test;
  217. s_LastTest = test;
  218. }
  219. }
  220.  
  221. // Dump a stack trace to stdout
  222. void dumpStack(int topFunctionsToSkip)
  223. {
  224. topFunctionsToSkip += 1; // We always want to skip this dumpStack() function
  225. void * array[64];
  226. size_t size = backtrace(array, 64);
  227. backtrace_symbols_fd(array + topFunctionsToSkip, size - topFunctionsToSkip, 1); // Adjust the array pointer to skip n elements at top of stack
  228. }
  229.  
  230. // Handler for exception signals
  231. void crashHandler(int sig)
  232. {
  233.  
  234. fprintf(stdout, "\nGot signal %d in crash handler\n", sig);
  235. fflush(stdout);
  236.  
  237. dumpStack(1);
  238.  
  239. _exit(1);
  240. }
  241.  
  242. // Handler for failed asserts
  243. void assertHandler(const char * file, int line, const char * message)
  244. {
  245. fprintf(stdout, "\nAssert failed (%s:%d):\n", file, line);
  246. fprintf(stdout, " %s\n", message);
  247. fflush(stdout);
  248.  
  249. dumpStack(1);
  250.  
  251. _exit(1);
  252. }
  253.  
Runtime error #stdin #stdout 0.01s 2856KB
stdin
Standard input is empty
stdout
Running tests...
prog.cpp:TestPass1... Ok
prog.cpp:TestPass2... Ok
prog.cpp:TestAssertFailed... 
Assert failed (prog.cpp:89):
    1 == false
./prog(__gxx_personality_v0+0x35f)[0x8048a0f]
./prog(__gxx_personality_v0+0x3fe)[0x8048aae]
./prog[0x8048c2a]
/lib/libc.so.6(__libc_start_main+0xe5)[0xb7646725]
./prog(__gxx_personality_v0+0x51)[0x8048701]
FAILED
prog.cpp:TestSegFault... 
Got signal 11 in crash handler
[0xb789e400]
./prog(__gxx_personality_v0+0x130)[0x80487e0]
./prog(__gxx_personality_v0+0x51)[0x8048701]
FAILED

*** TEST FAILED ***
2/4 Tests Passed