Print this page
    
Incorporate rmustacc's review feedback.
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/test/libc-tests/tests/common/test_common.c
          +++ new/usr/src/test/libc-tests/tests/common/test_common.c
   1    1  /*
   2    2   * This file and its contents are supplied under the terms of the
  
    | ↓ open down ↓ | 2 lines elided | ↑ open up ↑ | 
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13      - * Copyright 2014 Garrett D'Amore <garrett@damore.org>
       13 + * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  14   14   */
  15   15  
  16   16  /*
  17   17   * Common handling for test programs.
  18   18   */
  19   19  
  20   20  #include <stdio.h>
  21   21  #include <stdlib.h>
  22   22  #include <stdarg.h>
  23   23  #include <string.h>
  24   24  #include <errno.h>
  25   25  #include <pthread.h>
  26   26  #include <ctype.h>
  27   27  #include <unistd.h>
  28   28  #include <sys/param.h>
  29   29  #include "test_common.h"
  30   30  
  31   31  static int debug = 0;
  32   32  static int force = 0;
  33   33  static pthread_mutex_t lk;
  34   34  
  35   35  static int passes;
  36   36  static int tests;
  37   37  
  38   38  struct test {
  39   39          char            *name;
  40   40          int             ntids;
  41   41          pthread_t       *tids;
  42   42          int             fails;
  43   43          void            *arg;
  44   44          void            (*func)(test_t t, void *);
  45   45  };
  46   46  
  47   47  void
  48   48  test_set_debug(void)
  49   49  {
  50   50          debug++;
  51   51  }
  52   52  
  53   53  void
  54   54  test_set_force(void)
  55   55  {
  56   56          force++;
  57   57  }
  58   58  
  59   59  test_t
  60   60  test_start(const char *format, ...)
  61   61  {
  62   62          va_list args;
  63   63          test_t t;
  64   64          char *s;
  65   65  
  66   66          t = calloc(1, sizeof (*t));
  67   67          va_start(args, format);
  68   68          (void) vasprintf(&s, format, args);
  69   69          va_end(args);
  70   70  
  71   71          (void) asprintf(&t->name, "%s (%s)", s, ARCH);
  72   72          free(s);
  73   73  
  74   74          (void) pthread_mutex_lock(&lk);
  75   75          (void) printf("TEST STARTING %s:\n", t->name);
  76   76          (void) fflush(stdout);
  77   77          (void) pthread_mutex_unlock(&lk);
  78   78  
  79   79  #ifdef  LINT
  80   80          /* We inject references to make avoid name unused warnings */
  81   81          test_run(0, NULL, NULL, NULL);
  82   82          test_debugf(t, NULL);
  83   83          test_failed(t, NULL);
  84   84          test_passed(t);
  85   85          test_set_debug();
  86   86          test_set_force();
  87   87          test_summary();
  88   88          (void) test_load_config(t, NULL, NULL);
  89   89  #endif
  90   90  
  91   91          tests++;
  92   92          return (t);
  93   93  }
  94   94  
  95   95  void
  96   96  test_failed(test_t t, const char *format, ...)
  97   97  {
  98   98          va_list args;
  99   99  
 100  100          (void) pthread_mutex_lock(&lk);
 101  101          if (t == NULL) {
 102  102                  (void) printf("FAILURE: ");
 103  103                  va_start(args, format);
 104  104                  (void) vprintf(format, args);
 105  105                  va_end(args);
 106  106                  (void) printf("\n");
 107  107                  (void) fflush(stdout);
 108  108                  (void) pthread_mutex_unlock(&lk);
 109  109                  return;
 110  110          }
 111  111          if (force || (t->ntids > 0)) {
 112  112                  (void) printf("TEST FAILING %s: ", t->name);
 113  113          } else {
 114  114                  (void) printf("TEST FAILED %s: ", t->name);
 115  115          }
 116  116  
 117  117          va_start(args, format);
 118  118          (void) vprintf(format, args);
 119  119          va_end(args);
 120  120          (void) printf("\n");
 121  121          (void) fflush(stdout);
 122  122          (void) pthread_mutex_unlock(&lk);
 123  123  
 124  124          t->fails++;
 125  125          if (!force) {
 126  126                  if (t->ntids > 0) {
 127  127                          pthread_exit(NULL);
 128  128                  } else {
 129  129                          (void) exit(EXIT_FAILURE);
 130  130                  }
 131  131          }
 132  132  }
 133  133  
 134  134  void
 135  135  test_passed(test_t t)
 136  136  {
 137  137          if (t == NULL) {
 138  138                  return;
 139  139          }
 140  140          if (t->ntids > 0) {
 141  141                  if (debug) {
 142  142                          (void) pthread_mutex_lock(&lk);
 143  143                          (void) printf("TEST PASSING: %s\n", t->name);
 144  144                          (void) pthread_mutex_unlock(&lk);
 145  145                  }
 146  146                  return;
 147  147          }
 148  148          (void) pthread_mutex_lock(&lk);
 149  149          if (t->fails == 0) {
 150  150                  passes++;
 151  151                  (void) printf("TEST PASS: %s\n", t->name);
 152  152          } else {
 153  153                  (void) printf("TEST FAILED: %d failures\n", t->fails);
 154  154          }
 155  155          (void) fflush(stdout);
 156  156          (void) pthread_mutex_unlock(&lk);
 157  157          free(t->name);
 158  158          if (t->tids) {
 159  159                  free(t->tids);
 160  160          }
 161  161          free(t);
 162  162  }
 163  163  
  
    | ↓ open down ↓ | 140 lines elided | ↑ open up ↑ | 
 164  164  void
 165  165  test_summary(void)
 166  166  {
 167  167          if (passes == tests) {
 168  168                  (void) printf("TEST SUMMARY: %d / %d (ok)\n", passes, tests);
 169  169          } else {
 170  170                  (void) printf("TEST SUMMARY: %d / %d (%d failing)\n",
 171  171                      passes, tests, tests - passes);
 172  172          }
 173  173  }
      174 +
 174  175  void
 175  176  test_debugf(test_t t, const char *format, ...)
 176  177  {
 177  178          va_list args;
 178  179  
 179  180          if (!debug)
 180  181                  return;
 181  182  
 182  183          (void) pthread_mutex_lock(&lk);
 183  184          if (t) {
 184  185                  (void) printf("TEST DEBUG %s: ", t->name);
 185  186          } else {
 186  187                  (void) printf("TEST DEBUG: ");
 187  188          }
 188  189          va_start(args, format);
 189  190          (void) vprintf(format, args);
 190  191          va_end(args);
 191  192          (void) printf("\n");
 192  193          (void) fflush(stdout);
 193  194          (void) pthread_mutex_unlock(&lk);
 194  195  }
 195  196  
 196  197  static void *
 197  198  test_thr_one(void *arg)
 198  199  {
 199  200          test_t t = arg;
 200  201          t->func(t, t->arg);
 201  202          return (NULL);
 202  203  }
 203  204  
 204  205  void
 205  206  test_run(int nthr, void (*func)(test_t, void *), void *arg,
 206  207      const char *tname, ...)
 207  208  {
 208  209          test_t          t;
 209  210          char            *s;
 210  211          va_list         args;
 211  212  
 212  213          t = calloc(1, sizeof (*t));
 213  214          t->ntids = nthr;
 214  215          t->tids = calloc(nthr, sizeof (pthread_t));
 215  216          t->func = func;
 216  217          t->arg = arg;
 217  218  
 218  219          va_start(args, tname);
 219  220          (void) vasprintf(&s, tname, args);
 220  221          va_end(args);
 221  222  
 222  223          (void) asprintf(&t->name, "%s (%s)", s, ARCH);
 223  224          free(s);
 224  225  
 225  226          (void) pthread_mutex_lock(&lk);
 226  227          (void) printf("TEST STARTING %s:\n", t->name);
 227  228          (void) fflush(stdout);
 228  229          (void) pthread_mutex_unlock(&lk);
 229  230  
 230  231          test_debugf(t, "running %d threads", nthr);
 231  232  
 232  233          for (int i = 0; i < nthr; i++) {
 233  234                  test_debugf(t, "started thread %d", i);
 234  235                  (void) pthread_create(&t->tids[i], NULL, test_thr_one, t);
 235  236          }
 236  237  
 237  238          for (int i = 0; i < nthr; i++) {
 238  239                  (void) pthread_join(t->tids[i], NULL);
 239  240                  test_debugf(t, "thread %d joined", i);
 240  241                  t->ntids--;
 241  242          }
 242  243          test_passed(t);
 243  244  }
 244  245  
 245  246  void
 246  247  test_trim(char **ptr)
 247  248  {
 248  249          char *p = *ptr;
 249  250          while (isspace(*p)) {
 250  251                  p++;
 251  252          }
 252  253          *ptr = p;
 253  254          p += strlen(p);
 254  255          while ((--p >= *ptr) && (isspace(*p))) {
 255  256                  *p = 0;
 256  257          }
 257  258  }
 258  259  
 259  260  #define MAXCB           20
 260  261  #define MAXFIELD        20
 261  262  
 262  263  int
 263  264  test_load_config(test_t t, const char *fname, ...)
 264  265  {
 265  266          va_list         va;
 266  267          const char      *keyws[MAXCB];
 267  268          test_cfg_func_t callbs[MAXCB];
 268  269          char            *fields[MAXFIELD];
 269  270          int             nfields;
 270  271  
 271  272          FILE            *cfg;
  
    | ↓ open down ↓ | 88 lines elided | ↑ open up ↑ | 
 272  273          char            line[1024];
 273  274          char            buf[1024];
 274  275          int             done;
 275  276          char            *ptr;
 276  277          char            *tok;
 277  278          char            *err;
 278  279          int             lineno;
 279  280          int             rv;
 280  281          int             found;
 281  282          char            path[MAXPATHLEN];
      283 +        int             i;
 282  284  
 283  285          va_start(va, fname);
 284      -        for (int i = 0; i < MAXCB; i++) {
      286 +        for (i = 0; i < MAXCB; i++) {
 285  287                  keyws[i] = (const char *)va_arg(va, const char *);
 286  288                  if (keyws[i] == NULL)
 287  289                          break;
 288  290                  callbs[i] = (test_cfg_func_t)va_arg(va, test_cfg_func_t);
 289  291          }
 290  292          va_end(va);
      293 +        if (i == MAXCB) {
      294 +                test_debugf(t, "too many arguments to function >= %d", MAXCB);
      295 +        }
 291  296  
 292  297          found = 0;
 293  298  
 294  299          if (access(fname, F_OK) == 0) {
 295  300                  found++;
 296  301          }
 297  302          if (!found && fname[0] != '/') {
 298  303                  char *stf = getenv("STF_SUITE");
 299  304                  if (stf == NULL) {
 300  305                          stf = "../..";
 301  306                  }
 302  307                  (void) snprintf(path, sizeof (path), "%s/cfg/%s", stf, fname);
 303  308                  if (access(path, F_OK) == 0) {
 304  309                          fname = path;
 305  310                          found++;
 306  311                  } else {
 307  312                          (void) snprintf(path, sizeof (path), "cfg/%s", fname);
 308  313                          if (access(path, F_OK) == 0) {
 309  314                                  fname = path;
 310  315                                  found++;
 311  316                          }
 312  317                  }
 313  318          }
 314  319  
 315  320          if ((cfg = fopen(fname, "r")) ==  NULL) {
 316  321                  test_failed(t, "open(%s): %s", fname, strerror(errno));
 317  322                  return (-1);
 318  323          }
 319  324  
 320  325          line[0] = 0;
 321  326          done = 0;
 322  327          lineno = 0;
 323  328  
 324  329          while (!done) {
 325  330  
 326  331                  lineno++;
 327  332  
 328  333                  if (fgets(buf, sizeof (buf), cfg) == NULL) {
 329  334                          done++;
 330  335                  } else {
 331  336                          (void) strtok(buf, "\n");
 332  337                          if ((*buf != 0) && (buf[strlen(buf)-1] == '\\')) {
 333  338                                  /*
 334  339                                   * Continuation.  This isn't quite right,
 335  340                                   * as it doesn't allow for a "\" at the
 336  341                                   * end of line (no escaping).
 337  342                                   */
 338  343                                  buf[strlen(buf)-1] = 0;
 339  344                                  (void) strlcat(line, buf, sizeof (line));
 340  345                                  continue;
 341  346                          }
 342  347                          (void) strlcat(line, buf, sizeof (line));
 343  348                  }
 344  349  
 345  350                  /* got a line */
 346  351                  ptr = line;
 347  352                  test_trim(&ptr);
 348  353  
 349  354                  /* skip comments and empty lines */
 350  355                  if (ptr[0] == 0 || ptr[0] == '#') {
 351  356                          line[0] = 0;
 352  357                          continue;
 353  358                  }
 354  359  
 355  360                  tok = strsep(&ptr, "|");
 356  361                  if (tok == NULL) {
 357  362                          break;
 358  363                  }
 359  364                  test_trim(&tok);
 360  365  
 361  366                  for (nfields = 0; nfields < MAXFIELD; nfields++) {
 362  367                          fields[nfields] = strsep(&ptr, "|");
 363  368                          if (fields[nfields] == NULL) {
 364  369                                  break;
 365  370                          }
 366  371                          test_trim(&fields[nfields]);
 367  372                  }
 368  373  
 369  374                  found = 0;
 370  375                  rv = 0;
 371  376  
 372  377                  for (int i = 0; keyws[i] != NULL; i++) {
 373  378                          if (strcmp(tok, keyws[i]) == 0) {
 374  379                                  found++;
 375  380                                  err = NULL;
 376  381                                  rv = callbs[i](fields, nfields, &err);
 377  382                          }
 378  383                  }
 379  384                  if (!found) {
 380  385                          rv = -1;
 381  386                          err = NULL;
 382  387                          (void) asprintf(&err, "unknown keyword %s", tok);
 383  388                  }
 384  389                  if (rv != 0) {
 385  390                          if (err) {
 386  391                                  test_failed(t, "%s:%d: %s", fname,
 387  392                                      lineno, err);
 388  393                                  free(err);
 389  394                          } else {
 390  395                                  test_failed(t, "%s:%d: unknown error",
 391  396                                      fname, lineno);
 392  397                          }
 393  398                          (void) fclose(cfg);
 394  399                          return (rv);
 395  400                  }
 396  401  
 397  402                  line[0] = 0;
 398  403          }
 399  404          (void) fclose(cfg);
 400  405          return (0);
 401  406  }
  
    | ↓ open down ↓ | 101 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX