Project Ne10
An Open Optimized Software Library Project for the ARM Architecture
seatest.c
1 #include "seatest.h"
2 #include <string.h>
3 #ifdef WIN32
4 #include "windows.h"
5 int seatest_is_string_equal_i(const char* s1, const char* s2)
6 {
7  #pragma warning(disable: 4996)
8  return stricmp(s1, s2) == 0;
9 }
10 
11 #else
12 #include <sys/time.h>
13 
14 long int GetTickCount()
15 {
16 //#ifndef __MACH__
17 // struct timespec tv;
18 // clock_gettime(CLOCK_MONOTONIC, &tv);
19 // return tv.tv_sec*1000000 + tv.tv_nsec/1000;
20 //
21 //#else
22  struct timeval tv;
23  gettimeofday(&tv, NULL);
24  return tv.tv_sec*1000000 + tv.tv_usec;
25 //#endif
26 }
27 void _getch( void ) { }
28 int seatest_is_string_equal_i(const char* s1, const char* s2)
29 {
30  return strcasecmp(s1, s2) == 0;
31 }
32 #endif
33 
34 #ifdef SEATEST_INTERNAL_TESTS
35 static int sea_test_last_passed = 0;
36 #endif
37 
38 typedef enum
39 {
40  SEATEST_DISPLAY_TESTS,
41  SEATEST_RUN_TESTS,
42  SEATEST_DO_NOTHING,
43  SEATEST_DO_ABORT
44 } seatest_action_t;
45 
46 typedef struct
47 {
48  int argc;
49  char** argv;
50  seatest_action_t action;
52 static int seatest_screen_width = 70;
53 static int sea_tests_run = 0;
54 static int sea_tests_passed = 0;
55 static int sea_tests_failed = 0;
56 static int seatest_display_only = 0;
57 static int seatest_verbose = 0;
58 static int seatest_machine_readable = 0;
59 static char* seatest_current_fixture;
60 static char* seatest_current_fixture_path;
61 static char seatest_magic_marker[20] = "";
62 
63 static seatest_void_void seatest_suite_setup_func = 0;
64 static seatest_void_void seatest_suite_teardown_func = 0;
65 static seatest_void_void seatest_fixture_setup = 0;
66 static seatest_void_void seatest_fixture_teardown = 0;
67 
68 void (*seatest_simple_test_result)(int passed, char* reason, const char* function, unsigned int line) = seatest_simple_test_result_log;
69 
70 void suite_setup(seatest_void_void setup)
71 {
72  seatest_suite_setup_func = setup;
73 }
74 void suite_teardown(seatest_void_void teardown)
75 {
76  seatest_suite_teardown_func = teardown;
77 }
78 
79 int seatest_is_display_only()
80 {
81  return seatest_display_only;
82 }
83 
84 void seatest_suite_setup( void )
85 {
86  if(seatest_suite_setup_func != 0) seatest_suite_setup_func();
87 }
88 
89 void seatest_suite_teardown( void )
90 {
91  if(seatest_suite_teardown_func != 0) seatest_suite_teardown_func();
92 }
93 
94 void fixture_setup(void (*setup)( void ))
95 {
96  seatest_fixture_setup = setup;
97 }
98 void fixture_teardown(void (*teardown)( void ))
99 {
100  seatest_fixture_teardown = teardown;
101 }
102 
103 void seatest_setup( void )
104 {
105  if(seatest_fixture_setup != 0) seatest_fixture_setup();
106 }
107 
108 void seatest_teardown( void )
109 {
110  if(seatest_fixture_teardown != 0) seatest_fixture_teardown();
111 }
112 
113 char* test_file_name(char* path)
114 {
115  char* file = path + strlen(path);
116  while(file != path && *file!= '\\' ) file--;
117  if(*file == '\\') file++;
118  return file;
119 }
120 
121 static int seatest_fixture_tests_run;
122 static int seatest_fixture_tests_failed;
123 
124 void seatest_simple_test_result_log(int passed, char* reason, const char* function, unsigned int line)
125 {
126  if (!passed)
127  {
128 
129  if(seatest_machine_readable)
130  {
131  printf("%s%s,%s,%u,%s\r\n", seatest_magic_marker, seatest_current_fixture_path, function, line, reason );
132  }
133  else
134  {
135  printf("%-30s Line %-5d %s\r\n", function, line, reason );
136  }
137  sea_tests_failed++;
138  }
139  else
140  {
141  if(seatest_verbose)
142  {
143  if(seatest_machine_readable)
144  {
145  printf("%s%s,%s,%u,Passed\r\n", seatest_magic_marker, seatest_current_fixture_path, function, line );
146  }
147  else
148  {
149  printf("%-30s Line %-5d Passed\r\n", function, line);
150  }
151  }
152  sea_tests_passed++;
153  }
154 }
155 
156 void seatest_assert_true(int test, const char* function, unsigned int line)
157 {
158  seatest_simple_test_result(test, "Should have been true", function, line);
159 
160 }
161 
162 void seatest_assert_false(int test, const char* function, unsigned int line)
163 {
164  seatest_simple_test_result(!test, "Should have been false", function, line);
165 }
166 
167 
168 void seatest_assert_int_equal(int expected, int actual, const char* function, unsigned int line)
169 {
170  char s[SEATEST_PRINT_BUFFER_SIZE];
171  sprintf(s, "Expected %d but was %d", expected, actual);
172  seatest_simple_test_result(expected==actual, s, function, line);
173 }
174 
175 void seatest_assert_ulong_equal(unsigned long expected, unsigned long actual, const char* function, unsigned int line)
176 {
177  char s[SEATEST_PRINT_BUFFER_SIZE];
178  sprintf(s, "Expected %lu but was %lu", expected, actual);
179  seatest_simple_test_result(expected==actual, s, function, line);
180 }
181 
182 void seatest_assert_float_vec_equal( float expected, float actual, unsigned int delta, unsigned int seatest_vec, const char* function, unsigned int line )
183 {
184  char s[SEATEST_PRINT_BUFFER_SIZE];
185  if (!EQUALS_FLOAT(expected, actual, delta))
186  {
187  sprintf(s, "Expected %e (0x%04X) but was %e (0x%04X) at vector->%d ",
188  expected, *(unsigned int*)&expected, actual, *(unsigned int*)&actual, seatest_vec);
189  seatest_simple_test_result( 0, s, function, line);
190  }
191 }
192 
193 void seatest_assert_float_equal( float expected, float actual, unsigned int delta, unsigned int loop_round, const char* function, unsigned int line )
194 {
195  char s[SEATEST_PRINT_BUFFER_SIZE];
196  if (!EQUALS_FLOAT(expected, actual, delta))
197  {
198  sprintf(s, "Expected %e (0x%04X) but was %e (0x%04X) in loop round %d",
199  expected, *(unsigned int*)&expected, actual, *(unsigned int*)&actual, loop_round);
200  seatest_simple_test_result( 0, s, function, line);
201  }
202 }
203 
204 void seatest_assert_double_equal( double expected, double actual, double delta, const char* function, unsigned int line )
205 {
206  char s[SEATEST_PRINT_BUFFER_SIZE];
207  double result = expected-actual;
208  sprintf(s, "Expected %f but was %f", expected, actual);
209  if(result < 0.0) result = 0.0 - result;
210  seatest_simple_test_result( result <= delta, s, function, line);
211 }
212 
213 void seatest_assert_string_equal(char* expected, char* actual, const char* function, unsigned int line)
214 {
215  int comparison;
216  char s[SEATEST_PRINT_BUFFER_SIZE];
217 
218  if ((expected == (char *)0) && (actual == (char *)0))
219  {
220  sprintf(s, "Expected <NULL> but was <NULL>");
221  comparison = 1;
222  }
223  else if ((expected == (char *)0))
224  {
225  sprintf(s, "Expected <NULL> but was %s", actual);
226  comparison = 0;
227  }
228  else if ((actual == (char *)0))
229  {
230  sprintf(s, "Expected %s but was <NULL>", expected);
231  comparison = 0;
232  }
233  else
234  {
235  comparison = strcmp(expected, actual) == 0;
236  sprintf(s, "Expected %s but was %s", expected, actual);
237  }
238 
239  seatest_simple_test_result(comparison, s, function, line);
240 }
241 
242 void seatest_assert_string_ends_with(char* expected, char* actual, const char* function, unsigned int line)
243 {
244  char s[SEATEST_PRINT_BUFFER_SIZE];
245  sprintf(s, "Expected %s to end with %s", actual, expected);
246  seatest_simple_test_result(strcmp(expected, actual+(strlen(actual)-strlen(expected)))==0, s, function, line);
247 }
248 
249 void seatest_assert_string_starts_with(char* expected, char* actual, const char* function, unsigned int line)
250 {
251  char s[SEATEST_PRINT_BUFFER_SIZE];
252  sprintf(s, "Expected %s to start with %s", actual, expected);
253  seatest_simple_test_result(strncmp(expected, actual, strlen(expected))==0, s, function, line);
254 }
255 
256 void seatest_assert_string_contains(char* expected, char* actual, const char* function, unsigned int line)
257 {
258  char s[SEATEST_PRINT_BUFFER_SIZE];
259  sprintf(s, "Expected %s to be in %s", expected, actual);
260  seatest_simple_test_result(strstr(actual, expected)!=0, s, function, line);
261 }
262 
263 void seatest_assert_string_doesnt_contain(char* expected, char* actual, const char* function, unsigned int line)
264 {
265  char s[SEATEST_PRINT_BUFFER_SIZE];
266  sprintf(s, "Expected %s not to have %s in it", actual, expected);
267  seatest_simple_test_result(strstr(actual, expected)==0, s, function, line);
268 }
269 
270 void seatest_run_test(char* fixture, char* test)
271 {
272  sea_tests_run++;
273 }
274 
275 void seatest_header_printer(char* s, int length, char f)
276 {
277  int l = strlen(s);
278  int d = (length- (l + 2)) / 2;
279  int i;
280  if(seatest_is_display_only() || seatest_machine_readable) return;
281  for(i = 0; i<d; i++) printf("%c",f);
282  if(l==0) printf("%c%c", f, f);
283  else printf(" %s ", s);
284  for(i = (d+l+2); i<length; i++) printf("%c",f);
285  printf("\r\n");
286 }
287 
288 
289 void seatest_test_fixture_start(char* filepath)
290 {
291  seatest_current_fixture_path = filepath;
292  seatest_current_fixture = test_file_name(filepath);
293  seatest_header_printer(seatest_current_fixture, seatest_screen_width, '-');
294  seatest_fixture_tests_failed = sea_tests_failed;
295  seatest_fixture_tests_run = sea_tests_run;
296  seatest_fixture_teardown = 0;
297  seatest_fixture_setup = 0;
298 }
299 
300 void seatest_test_fixture_end()
301 {
302  char s[SEATEST_PRINT_BUFFER_SIZE];
303  sprintf(s, "%d run %d failed", sea_tests_run-seatest_fixture_tests_run, sea_tests_failed-seatest_fixture_tests_failed);
304  seatest_header_printer(s, seatest_screen_width, ' ');
305  printf("\r\n");
306 }
307 
308 static char* seatest_fixture_filter = 0;
309 static char* seatest_test_filter = 0;
310 
311 void fixture_filter(char* filter)
312 {
313  seatest_fixture_filter = filter;
314 }
315 
316 
317 void test_filter(char* filter)
318 {
319  seatest_test_filter = filter;
320 }
321 
322 void set_magic_marker(char* marker)
323 {
324  if(marker == NULL) return;
325  strcpy(seatest_magic_marker, marker);
326 }
327 
328 void seatest_display_test(char* fixture_name, char* test_name)
329 {
330  if(test_name == NULL) return;
331  printf("%s,%s\r\n", fixture_name, test_name);
332 }
333 
334 int seatest_should_run( char* fixture, char* test)
335 {
336  int run = 1;
337  if(seatest_fixture_filter)
338  {
339  if(strncmp(seatest_fixture_filter, fixture, strlen(seatest_fixture_filter)) != 0) run = 0;
340  }
341  if(seatest_test_filter && test != NULL)
342  {
343  if(strncmp(seatest_test_filter, test, strlen(seatest_test_filter)) != 0) run = 0;
344  }
345 
346  if(run && seatest_display_only)
347  {
348  seatest_display_test(fixture, test);
349  run = 0;
350  }
351  return run;
352 }
353 
354 int run_tests(seatest_void_void tests)
355 {
356  unsigned long long end;
357  unsigned long long start = GetTickCount();
358  char version[40];
359  char s[40];
360  tests();
361  end = GetTickCount();
362 
363  if(seatest_is_display_only() || seatest_machine_readable) return 1;
364  sprintf(version, "SEATEST v%s", SEATEST_VERSION);
365  printf("\r\n\r\n");
366  seatest_header_printer(version, seatest_screen_width, '=');
367  printf("\r\n");
368  if (sea_tests_failed > 0) {
369  seatest_header_printer("Failed", seatest_screen_width, ' ');
370  }
371  else {
372  seatest_header_printer("ALL TESTS PASSED", seatest_screen_width, ' ');
373  }
374  sprintf(s,"%d tests run", sea_tests_run);
375  seatest_header_printer(s, seatest_screen_width, ' ');
376  sprintf(s,"in %llu micro-s",end - start);
377  seatest_header_printer(s, seatest_screen_width, ' ');
378  printf("\r\n");
379  seatest_header_printer("", seatest_screen_width, '=');
380 
381  return sea_tests_failed == 0;
382 }
383 
384 
385 void seatest_show_help( void )
386 {
387  printf("Usage: [-t <testname>] [-f <fixturename>] [-d] [help] [-v] [-m] [-k <marker>\r\n");
388  printf("Flags:\r\n");
389  printf("\thelp:\twill display this help\r\n");
390  printf("\t-t:\twill only run tests that match <testname>\r\n");
391  printf("\t-f:\twill only run fixtures that match <fixturename>\r\n");
392  printf("\t-d:\twill just display test names and fixtures without\r\n");
393  printf("\t-d:\trunning the test\r\n");
394  printf("\t-v:\twill print a more verbose version of the test run\r\n");
395  printf("\t-m:\twill print a machine readable format of the test run, ie :- \r\n");
396  printf("\t \t<textfixture>,<testname>,<linenumber>,<testresult><EOL>\r\n");
397  printf("\t-k:\twill prepend <marker> before machine readable output \r\n");
398  printf("\t \t<marker> cannot start with a '-'\r\n");
399 }
400 
401 
402 int seatest_commandline_has_value_after(seatest_testrunner_t* runner, int arg)
403 {
404  if(!((arg+1) < runner->argc)) return 0;
405  if(runner->argv[arg+1][0]=='-') return 0;
406  return 1;
407 }
408 
409 int seatest_parse_commandline_option_with_value(seatest_testrunner_t* runner, int arg, char* option, seatest_void_string setter)
410 {
411  if(seatest_is_string_equal_i(runner->argv[arg], option))
412  {
413  if(!seatest_commandline_has_value_after(runner, arg))
414  {
415  printf("Error: The %s option expects to be followed by a value\r\n", option);
416  runner->action = SEATEST_DO_ABORT;
417  return 0;
418  }
419  setter(runner->argv[arg+1]);
420  return 1;
421  }
422  return 0;
423 }
424 
425 void seatest_interpret_commandline(seatest_testrunner_t* runner)
426 {
427  int arg;
428  for(arg=0; (arg < runner->argc) && (runner->action != SEATEST_DO_ABORT); arg++)
429  {
430  if(seatest_is_string_equal_i(runner->argv[arg], "help"))
431  {
432  seatest_show_help();
433  runner->action = SEATEST_DO_NOTHING;
434  return;
435  }
436  if(seatest_is_string_equal_i(runner->argv[arg], "-d")) runner->action = SEATEST_DISPLAY_TESTS;
437  if(seatest_is_string_equal_i(runner->argv[arg], "-v")) seatest_verbose = 1;
438  if(seatest_is_string_equal_i(runner->argv[arg], "-m")) seatest_machine_readable = 1;
439  if(seatest_parse_commandline_option_with_value(runner,arg,"-t", test_filter)) arg++;
440  if(seatest_parse_commandline_option_with_value(runner,arg,"-f", fixture_filter)) arg++;
441  if(seatest_parse_commandline_option_with_value(runner,arg,"-k", set_magic_marker)) arg++;
442  }
443 }
444 
445 void seatest_testrunner_create(seatest_testrunner_t* runner, int argc, char** argv )
446 {
447  runner->action = SEATEST_RUN_TESTS;
448  runner->argc = argc;
449  runner->argv = argv;
450  seatest_interpret_commandline(runner);
451 }
452 
453 int seatest_testrunner(int argc, char** argv, seatest_void_void tests, seatest_void_void setup, seatest_void_void teardown)
454 {
455  seatest_testrunner_t runner;
456  seatest_testrunner_create(&runner, argc, argv);
457  switch(runner.action)
458  {
459  case SEATEST_DISPLAY_TESTS:
460  {
461  seatest_display_only = 1;
462  run_tests(tests);
463  break;
464  }
465  case SEATEST_RUN_TESTS:
466  {
467  suite_setup(setup);
468  suite_teardown(teardown);
469  return run_tests(tests);
470  }
471  case SEATEST_DO_NOTHING:
472  case SEATEST_DO_ABORT:
473  default:
474  {
475  /* nothing to do, probably because there was an error which should of been already printed out. */
476  }
477  }
478  return 1;
479 }
480 
481 #ifdef SEATEST_INTERNAL_TESTS
482 void seatest_simple_test_result_nolog(int passed, char* reason, const char* function, unsigned int line)
483 {
484  sea_test_last_passed = passed;
485 }
486 
487 void seatest_assert_last_passed()
488 {
489  assert_int_equal(1, sea_test_last_passed);
490 }
491 
492 void seatest_assert_last_failed()
493 {
494  assert_int_equal(0, sea_test_last_passed);
495 }
496 
497 void seatest_disable_logging()
498 {
499  seatest_simple_test_result = seatest_simple_test_result_nolog;
500 }
501 
502 void seatest_enable_logging()
503 {
504  seatest_simple_test_result = seatest_simple_test_result_log;
505 }
506 #endif