root/opal/mca/event/libevent2022/libevent/test/tinytest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _testcase_run_bare
  2. _testcase_run_forked
  3. testcase_run_one
  4. _tinytest_set_flag
  5. usage
  6. tinytest_main
  7. _tinytest_get_verbosity
  8. _tinytest_set_test_failed
  9. _tinytest_set_test_skipped

   1 /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
   2  *
   3  * Redistribution and use in source and binary forms, with or without
   4  * modification, are permitted provided that the following conditions
   5  * are met:
   6  * 1. Redistributions of source code must retain the above copyright
   7  *    notice, this list of conditions and the following disclaimer.
   8  * 2. Redistributions in binary form must reproduce the above copyright
   9  *    notice, this list of conditions and the following disclaimer in the
  10  *    documentation and/or other materials provided with the distribution.
  11  * 3. The name of the author may not be used to endorse or promote products
  12  *    derived from this software without specific prior written permission.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <assert.h>
  30 
  31 #ifdef TINYTEST_LOCAL
  32 #include "tinytest_local.h"
  33 #endif
  34 
  35 #ifdef WIN32
  36 #include <windows.h>
  37 #else
  38 #include <sys/types.h>
  39 #include <sys/wait.h>
  40 #include <unistd.h>
  41 #endif
  42 
  43 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
  44 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
  45     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
  46 /* Workaround for a stupid bug in OSX 10.6 */
  47 #define FORK_BREAKS_GCOV
  48 #include <vproc.h>
  49 #endif
  50 #endif
  51 
  52 #ifndef __GNUC__
  53 #define __attribute__(x)
  54 #endif
  55 
  56 #include "tinytest.h"
  57 #include "tinytest_macros.h"
  58 
  59 #define LONGEST_TEST_NAME 16384
  60 
  61 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
  62 static int n_ok = 0; /**< Number of tests that have passed */
  63 static int n_bad = 0; /**< Number of tests that have failed. */
  64 static int n_skipped = 0; /**< Number of tests that have been skipped. */
  65 
  66 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
  67 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
  68 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
  69 const char *verbosity_flag = "";
  70 
  71 enum outcome { SKIP=2, OK=1, FAIL=0 };
  72 static enum outcome cur_test_outcome = 0;
  73 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
  74 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
  75 const char *cur_test_name = NULL;
  76 
  77 #ifdef WIN32
  78 /* Copy of argv[0] for win32. */
  79 static char commandname[MAX_PATH+1];
  80 #endif
  81 
  82 static void usage(struct testgroup_t *groups, int list_groups)
  83   __attribute__((noreturn));
  84 
  85 static enum outcome
  86 _testcase_run_bare(const struct testcase_t *testcase)
  87 {
  88         void *env = NULL;
  89         int outcome;
  90         if (testcase->setup) {
  91                 env = testcase->setup->setup_fn(testcase);
  92                 if (!env)
  93                         return FAIL;
  94                 else if (env == (void*)TT_SKIP)
  95                         return SKIP;
  96         }
  97 
  98         cur_test_outcome = OK;
  99         testcase->fn(env);
 100         outcome = cur_test_outcome;
 101 
 102         if (testcase->setup) {
 103                 if (testcase->setup->cleanup_fn(testcase, env) == 0)
 104                         outcome = FAIL;
 105         }
 106 
 107         return outcome;
 108 }
 109 
 110 #define MAGIC_EXITCODE 42
 111 
 112 static enum outcome
 113 _testcase_run_forked(const struct testgroup_t *group,
 114                      const struct testcase_t *testcase)
 115 {
 116 #ifdef WIN32
 117         /* Fork? On Win32?  How primitive!  We'll do what the smart kids do:
 118            we'll invoke our own exe (whose name we recall from the command
 119            line) with a command line that tells it to run just the test we
 120            want, and this time without forking.
 121 
 122            (No, threads aren't an option.  The whole point of forking is to
 123            share no state between tests.)
 124          */
 125         int ok;
 126         char buffer[LONGEST_TEST_NAME+256];
 127         STARTUPINFOA si;
 128         PROCESS_INFORMATION info;
 129         DWORD exitcode;
 130 
 131         if (!in_tinytest_main) {
 132                 printf("\nERROR.  On Windows, _testcase_run_forked must be"
 133                        " called from within tinytest_main.\n");
 134                 abort();
 135         }
 136         if (opt_verbosity>0)
 137                 printf("[forking] ");
 138 
 139         snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
 140                  commandname, verbosity_flag, group->prefix, testcase->name);
 141 
 142         memset(&si, 0, sizeof(si));
 143         memset(&info, 0, sizeof(info));
 144         si.cb = sizeof(si);
 145 
 146         ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
 147                            0, NULL, NULL, &si, &info);
 148         if (!ok) {
 149                 printf("CreateProcess failed!\n");
 150                 return 0;
 151         }
 152         WaitForSingleObject(info.hProcess, INFINITE);
 153         GetExitCodeProcess(info.hProcess, &exitcode);
 154         CloseHandle(info.hProcess);
 155         CloseHandle(info.hThread);
 156         if (exitcode == 0)
 157                 return OK;
 158         else if (exitcode == MAGIC_EXITCODE)
 159                 return SKIP;
 160         else
 161                 return FAIL;
 162 #else
 163         int outcome_pipe[2];
 164         pid_t pid;
 165         (void)group;
 166 
 167         if (pipe(outcome_pipe))
 168                 perror("opening pipe");
 169 
 170         if (opt_verbosity>0)
 171                 printf("[forking] ");
 172         pid = fork();
 173 #ifdef FORK_BREAKS_GCOV
 174         vproc_transaction_begin(0);
 175 #endif
 176         if (!pid) {
 177                 /* child. */
 178                 int test_r, write_r;
 179                 char b[1];
 180                 close(outcome_pipe[0]);
 181                 test_r = _testcase_run_bare(testcase);
 182                 assert(0<=(int)test_r && (int)test_r<=2);
 183                 b[0] = "NYS"[test_r];
 184                 write_r = (int)write(outcome_pipe[1], b, 1);
 185                 if (write_r != 1) {
 186                         perror("write outcome to pipe");
 187                         exit(1);
 188                 }
 189                 exit(0);
 190                 return FAIL; /* unreachable */
 191         } else {
 192                 /* parent */
 193                 int status, r;
 194                 char b[1];
 195                 /* Close this now, so that if the other side closes it,
 196                  * our read fails. */
 197                 close(outcome_pipe[1]);
 198                 r = (int)read(outcome_pipe[0], b, 1);
 199                 if (r == 0) {
 200                         printf("[Lost connection!] ");
 201                         return 0;
 202                 } else if (r != 1) {
 203                         perror("read outcome from pipe");
 204                 }
 205                 waitpid(pid, &status, 0);
 206                 close(outcome_pipe[0]);
 207                 return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
 208         }
 209 #endif
 210 }
 211 
 212 int
 213 testcase_run_one(const struct testgroup_t *group,
 214                  const struct testcase_t *testcase)
 215 {
 216         enum outcome outcome;
 217 
 218         if (testcase->flags & TT_SKIP) {
 219                 if (opt_verbosity>0)
 220                         printf("%s%s: SKIPPED\n",
 221                             group->prefix, testcase->name);
 222                 ++n_skipped;
 223                 return SKIP;
 224         }
 225 
 226         if (opt_verbosity>0 && !opt_forked) {
 227                 printf("%s%s: ", group->prefix, testcase->name);
 228         } else {
 229                 if (opt_verbosity==0) printf(".");
 230                 cur_test_prefix = group->prefix;
 231                 cur_test_name = testcase->name;
 232         }
 233 
 234         if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
 235                 outcome = _testcase_run_forked(group, testcase);
 236         } else {
 237                 outcome = _testcase_run_bare(testcase);
 238         }
 239 
 240         if (outcome == OK) {
 241                 ++n_ok;
 242                 if (opt_verbosity>0 && !opt_forked)
 243                         puts(opt_verbosity==1?"OK":"");
 244         } else if (outcome == SKIP) {
 245                 ++n_skipped;
 246                 if (opt_verbosity>0 && !opt_forked)
 247                         puts("SKIPPED");
 248         } else {
 249                 ++n_bad;
 250                 if (!opt_forked)
 251                         printf("\n  [%s FAILED]\n", testcase->name);
 252         }
 253 
 254         if (opt_forked) {
 255                 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
 256                 return 1; /* unreachable */
 257         } else {
 258                 return (int)outcome;
 259         }
 260 }
 261 
 262 int
 263 _tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
 264 {
 265         int i, j;
 266         size_t length = LONGEST_TEST_NAME;
 267         char fullname[LONGEST_TEST_NAME];
 268         int found=0;
 269         if (strstr(arg, ".."))
 270                 length = strstr(arg,"..")-arg;
 271         for (i=0; groups[i].prefix; ++i) {
 272                 for (j=0; groups[i].cases[j].name; ++j) {
 273                         snprintf(fullname, sizeof(fullname), "%s%s",
 274                                  groups[i].prefix, groups[i].cases[j].name);
 275                         if (!flag) /* Hack! */
 276                                 printf("    %s\n", fullname);
 277                         if (!strncmp(fullname, arg, length)) {
 278                                 groups[i].cases[j].flags |= flag;
 279                                 ++found;
 280                         }
 281                 }
 282         }
 283         return found;
 284 }
 285 
 286 static void
 287 usage(struct testgroup_t *groups, int list_groups)
 288 {
 289         puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
 290         puts("  Specify tests by name, or using a prefix ending with '..'");
 291         puts("  To skip a test, list give its name prefixed with a colon.");
 292         puts("  Use --list-tests for a list of tests.");
 293         if (list_groups) {
 294                 puts("Known tests are:");
 295                 _tinytest_set_flag(groups, "..", 0);
 296         }
 297         exit(0);
 298 }
 299 
 300 int
 301 tinytest_main(int c, const char **v, struct testgroup_t *groups)
 302 {
 303         int i, j, n=0;
 304 
 305 #ifdef WIN32
 306         const char *sp = strrchr(v[0], '.');
 307         const char *extension = "";
 308         if (!sp || stricmp(sp, ".exe"))
 309                 extension = ".exe"; /* Add an exe so CreateProcess will work */
 310         snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
 311         commandname[MAX_PATH]='\0';
 312 #endif
 313         for (i=1; i<c; ++i) {
 314                 if (v[i][0] == '-') {
 315                         if (!strcmp(v[i], "--RUNNING-FORKED")) {
 316                                 opt_forked = 1;
 317                         } else if (!strcmp(v[i], "--no-fork")) {
 318                                 opt_nofork = 1;
 319                         } else if (!strcmp(v[i], "--quiet")) {
 320                                 opt_verbosity = -1;
 321                                 verbosity_flag = "--quiet";
 322                         } else if (!strcmp(v[i], "--verbose")) {
 323                                 opt_verbosity = 2;
 324                                 verbosity_flag = "--verbose";
 325                         } else if (!strcmp(v[i], "--terse")) {
 326                                 opt_verbosity = 0;
 327                                 verbosity_flag = "--terse";
 328                         } else if (!strcmp(v[i], "--help")) {
 329                                 usage(groups, 0);
 330                         } else if (!strcmp(v[i], "--list-tests")) {
 331                                 usage(groups, 1);
 332                         } else {
 333                                 printf("Unknown option %s.  Try --help\n",v[i]);
 334                                 return -1;
 335                         }
 336                 } else {
 337                         const char *test = v[i];
 338                         int flag = _TT_ENABLED;
 339                         if (test[0] == ':') {
 340                                 ++test;
 341                                 flag = TT_SKIP;
 342                         } else {
 343                                 ++n;
 344                         }
 345                         if (!_tinytest_set_flag(groups, test, flag)) {
 346                                 printf("No such test as %s!\n", v[i]);
 347                                 return -1;
 348                         }
 349                 }
 350         }
 351         if (!n)
 352                 _tinytest_set_flag(groups, "..", _TT_ENABLED);
 353 
 354         setvbuf(stdout, NULL, _IONBF, 0);
 355 
 356         ++in_tinytest_main;
 357         for (i=0; groups[i].prefix; ++i)
 358                 for (j=0; groups[i].cases[j].name; ++j)
 359                         if (groups[i].cases[j].flags & _TT_ENABLED)
 360                                 testcase_run_one(&groups[i],
 361                                                  &groups[i].cases[j]);
 362 
 363         --in_tinytest_main;
 364 
 365         if (opt_verbosity==0)
 366                 puts("");
 367 
 368         if (n_bad)
 369                 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
 370                        n_bad+n_ok,n_skipped);
 371         else if (opt_verbosity >= 1)
 372                 printf("%d tests ok.  (%d skipped)\n", n_ok, n_skipped);
 373 
 374         return (n_bad == 0) ? 0 : 1;
 375 }
 376 
 377 int
 378 _tinytest_get_verbosity(void)
 379 {
 380         return opt_verbosity;
 381 }
 382 
 383 void
 384 _tinytest_set_test_failed(void)
 385 {
 386         if (opt_verbosity <= 0 && cur_test_name) {
 387                 if (opt_verbosity==0) puts("");
 388                 printf("%s%s: ", cur_test_prefix, cur_test_name);
 389                 cur_test_name = NULL;
 390         }
 391         cur_test_outcome = 0;
 392 }
 393 
 394 void
 395 _tinytest_set_test_skipped(void)
 396 {
 397         if (cur_test_outcome==OK)
 398                 cur_test_outcome = SKIP;
 399 }
 400 

/* [<][>][^][v][top][bottom][index][help] */