Home | History | Annotate | Line # | Download | only in testutil
driver.c revision 1.1.1.4
      1 /*
      2  * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "../testutil.h"
     11 #include "output.h"
     12 #include "tu_local.h"
     13 
     14 #include <string.h>
     15 #include <assert.h>
     16 
     17 #include "internal/nelem.h"
     18 #include <openssl/bio.h>
     19 
     20 #include "platform.h"            /* From libapps */
     21 
     22 #if defined(_WIN32) && !defined(__BORLANDC__)
     23 # define strdup _strdup
     24 #endif
     25 
     26 
     27 /*
     28  * Declares the structures needed to register each test case function.
     29  */
     30 typedef struct test_info {
     31     const char *test_case_name;
     32     int (*test_fn) (void);
     33     int (*param_test_fn)(int idx);
     34     int num;
     35 
     36     /* flags */
     37     int subtest:1;
     38 } TEST_INFO;
     39 
     40 static TEST_INFO all_tests[1024];
     41 static int num_tests = 0;
     42 static int show_list = 0;
     43 static int single_test = -1;
     44 static int single_iter = -1;
     45 static int level = 0;
     46 static int seed = 0;
     47 static int rand_order = 0;
     48 
     49 /*
     50  * A parameterised test runs a loop of test cases.
     51  * |num_test_cases| counts the total number of non-subtest test cases
     52  * across all tests.
     53  */
     54 static int num_test_cases = 0;
     55 
     56 static int process_shared_options(void);
     57 
     58 
     59 void add_test(const char *test_case_name, int (*test_fn) (void))
     60 {
     61     assert(num_tests != OSSL_NELEM(all_tests));
     62     all_tests[num_tests].test_case_name = test_case_name;
     63     all_tests[num_tests].test_fn = test_fn;
     64     all_tests[num_tests].num = -1;
     65     ++num_tests;
     66     ++num_test_cases;
     67 }
     68 
     69 void add_all_tests(const char *test_case_name, int(*test_fn)(int idx),
     70                    int num, int subtest)
     71 {
     72     assert(num_tests != OSSL_NELEM(all_tests));
     73     all_tests[num_tests].test_case_name = test_case_name;
     74     all_tests[num_tests].param_test_fn = test_fn;
     75     all_tests[num_tests].num = num;
     76     all_tests[num_tests].subtest = subtest;
     77     ++num_tests;
     78     if (subtest)
     79         ++num_test_cases;
     80     else
     81         num_test_cases += num;
     82 }
     83 
     84 static int gcd(int a, int b)
     85 {
     86     while (b != 0) {
     87         int t = b;
     88         b = a % b;
     89         a = t;
     90     }
     91     return a;
     92 }
     93 
     94 static void set_seed(int s)
     95 {
     96     seed = s;
     97     if (seed <= 0)
     98         seed = (int)time(NULL);
     99     test_random_seed(seed);
    100 }
    101 
    102 
    103 int setup_test_framework(int argc, char *argv[])
    104 {
    105     char *test_seed = getenv("OPENSSL_TEST_RAND_ORDER");
    106     char *TAP_levels = getenv("HARNESS_OSSL_LEVEL");
    107 
    108     if (TAP_levels != NULL)
    109         level = 4 * atoi(TAP_levels);
    110     test_adjust_streams_tap_level(level);
    111     if (test_seed != NULL) {
    112         rand_order = 1;
    113         set_seed(atoi(test_seed));
    114     } else {
    115         set_seed(0);
    116     }
    117 
    118 #if defined(OPENSSL_SYS_VMS) && defined(__DECC)
    119     argv = copy_argv(&argc, argv);
    120 #elif defined(_WIN32)
    121     /*
    122      * Replace argv[] with UTF-8 encoded strings.
    123      */
    124     win32_utf8argv(&argc, &argv);
    125 #endif
    126 
    127     if (!opt_init(argc, argv, test_get_options()))
    128         return 0;
    129     return 1;
    130 }
    131 
    132 
    133 /*
    134  * This can only be called after setup() has run, since num_tests and
    135  * all_tests[] are setup at this point
    136  */
    137 static int check_single_test_params(char *name, char *testname, char *itname)
    138 {
    139     if (name != NULL) {
    140         int i;
    141         for (i = 0; i < num_tests; ++i) {
    142             if (strcmp(name, all_tests[i].test_case_name) == 0) {
    143                 single_test = 1 + i;
    144                 break;
    145             }
    146         }
    147         if (i >= num_tests)
    148             single_test = atoi(name);
    149     }
    150 
    151 
    152     /* if only iteration is specified, assume we want the first test */
    153     if (single_test == -1 && single_iter != -1)
    154         single_test = 1;
    155 
    156     if (single_test != -1) {
    157         if (single_test < 1 || single_test > num_tests) {
    158             test_printf_stderr("Invalid -%s value "
    159                                "(Value must be a valid test name OR a value between %d..%d)\n",
    160                                testname, 1, num_tests);
    161             return 0;
    162         }
    163     }
    164     if (single_iter != -1) {
    165         if (all_tests[single_test - 1].num == -1) {
    166             test_printf_stderr("-%s option is not valid for test %d:%s\n",
    167                                itname,
    168                                single_test,
    169                                all_tests[single_test - 1].test_case_name);
    170             return 0;
    171         } else if (single_iter < 1
    172                    || single_iter > all_tests[single_test - 1].num) {
    173             test_printf_stderr("Invalid -%s value for test %d:%s\t"
    174                                "(Value must be in the range %d..%d)\n",
    175                                itname, single_test,
    176                                all_tests[single_test - 1].test_case_name,
    177                                1, all_tests[single_test - 1].num);
    178             return 0;
    179         }
    180     }
    181     return 1;
    182 }
    183 
    184 static int process_shared_options(void)
    185 {
    186     OPTION_CHOICE_DEFAULT o;
    187     int value;
    188     int ret = -1;
    189     char *flag_test = "";
    190     char *flag_iter = "";
    191     char *testname = NULL;
    192 
    193     opt_begin();
    194     while ((o = opt_next()) != OPT_EOF) {
    195         switch (o) {
    196         /* Ignore any test options at this level */
    197         default:
    198             break;
    199         case OPT_ERR:
    200             return ret;
    201         case OPT_TEST_HELP:
    202             opt_help(test_get_options());
    203             return 0;
    204         case OPT_TEST_LIST:
    205             show_list = 1;
    206             break;
    207         case OPT_TEST_SINGLE:
    208             flag_test = opt_flag();
    209             testname = opt_arg();
    210             break;
    211         case OPT_TEST_ITERATION:
    212             flag_iter = opt_flag();
    213             if (!opt_int(opt_arg(), &single_iter))
    214                 goto end;
    215             break;
    216         case OPT_TEST_INDENT:
    217             if (!opt_int(opt_arg(), &value))
    218                 goto end;
    219             level = 4 * value;
    220             test_adjust_streams_tap_level(level);
    221             break;
    222         case OPT_TEST_SEED:
    223             if (!opt_int(opt_arg(), &value))
    224                 goto end;
    225             set_seed(value);
    226             break;
    227         }
    228     }
    229     if (!check_single_test_params(testname, flag_test, flag_iter))
    230         goto end;
    231     ret = 1;
    232 end:
    233     return ret;
    234 }
    235 
    236 
    237 int pulldown_test_framework(int ret)
    238 {
    239     set_test_title(NULL);
    240     return ret;
    241 }
    242 
    243 static void finalize(int success)
    244 {
    245     if (success)
    246         ERR_clear_error();
    247     else
    248         ERR_print_errors_cb(openssl_error_cb, NULL);
    249 }
    250 
    251 static char *test_title = NULL;
    252 
    253 void set_test_title(const char *title)
    254 {
    255     free(test_title);
    256     test_title = title == NULL ? NULL : strdup(title);
    257 }
    258 
    259 PRINTF_FORMAT(2, 3) static void test_verdict(int verdict,
    260                                              const char *description, ...)
    261 {
    262     va_list ap;
    263 
    264     test_flush_stdout();
    265     test_flush_stderr();
    266 
    267     if (verdict == 0 && seed != 0)
    268         test_printf_tapout("# OPENSSL_TEST_RAND_ORDER=%d\n", seed);
    269     test_printf_tapout("%s ", verdict != 0 ? "ok" : "not ok");
    270     va_start(ap, description);
    271     test_vprintf_tapout(description, ap);
    272     va_end(ap);
    273     if (verdict == TEST_SKIP_CODE)
    274         test_printf_tapout(" # skipped");
    275     test_printf_tapout("\n");
    276     test_flush_tapout();
    277 }
    278 
    279 int run_tests(const char *test_prog_name)
    280 {
    281     int num_failed = 0;
    282     int verdict = 1;
    283     int ii, i, jj, j, jstep;
    284     int test_case_count = 0;
    285     int subtest_case_count = 0;
    286     int permute[OSSL_NELEM(all_tests)];
    287 
    288     i = process_shared_options();
    289     if (i == 0)
    290         return EXIT_SUCCESS;
    291     if (i == -1)
    292         return EXIT_FAILURE;
    293 
    294     if (num_tests < 1) {
    295         test_printf_tapout("1..0 # Skipped: %s\n", test_prog_name);
    296     } else if (show_list == 0 && single_test == -1) {
    297         if (level > 0) {
    298             test_printf_stdout("Subtest: %s\n", test_prog_name);
    299             test_flush_stdout();
    300         }
    301         test_printf_tapout("1..%d\n", num_test_cases);
    302     }
    303 
    304     test_flush_tapout();
    305 
    306     for (i = 0; i < num_tests; i++)
    307         permute[i] = i;
    308     if (rand_order != 0)
    309         for (i = num_tests - 1; i >= 1; i--) {
    310             j = test_random() % (1 + i);
    311             ii = permute[j];
    312             permute[j] = permute[i];
    313             permute[i] = ii;
    314         }
    315 
    316     for (ii = 0; ii != num_tests; ++ii) {
    317         i = permute[ii];
    318 
    319         if (single_test != -1 && ((i+1) != single_test)) {
    320             continue;
    321         }
    322         else if (show_list) {
    323             if (all_tests[i].num != -1) {
    324                 test_printf_tapout("%d - %s (%d..%d)\n", ii + 1,
    325                                    all_tests[i].test_case_name, 1,
    326                                    all_tests[i].num);
    327             } else {
    328                 test_printf_tapout("%d - %s\n", ii + 1,
    329                                    all_tests[i].test_case_name);
    330             }
    331             test_flush_tapout();
    332         } else if (all_tests[i].num == -1) {
    333             set_test_title(all_tests[i].test_case_name);
    334             ERR_clear_error();
    335             verdict = all_tests[i].test_fn();
    336             finalize(verdict != 0);
    337             test_verdict(verdict, "%d - %s", test_case_count + 1, test_title);
    338             if (verdict == 0)
    339                 num_failed++;
    340             test_case_count++;
    341         } else {
    342             verdict = TEST_SKIP_CODE;
    343             set_test_title(all_tests[i].test_case_name);
    344             if (all_tests[i].subtest) {
    345                 level += 4;
    346                 test_adjust_streams_tap_level(level);
    347                 if (single_iter == -1) {
    348                     test_printf_stdout("Subtest: %s\n", test_title);
    349                     test_printf_tapout("%d..%d\n", 1, all_tests[i].num);
    350                     test_flush_stdout();
    351                     test_flush_tapout();
    352                 }
    353             }
    354 
    355             j = -1;
    356             if (rand_order == 0 || all_tests[i].num < 3)
    357                 jstep = 1;
    358             else
    359                 do
    360                     jstep = test_random() % all_tests[i].num;
    361                 while (jstep == 0 || gcd(all_tests[i].num, jstep) != 1);
    362 
    363             for (jj = 0; jj < all_tests[i].num; jj++) {
    364                 int v;
    365 
    366                 j = (j + jstep) % all_tests[i].num;
    367                 if (single_iter != -1 && ((jj + 1) != single_iter))
    368                     continue;
    369                 ERR_clear_error();
    370                 v = all_tests[i].param_test_fn(j);
    371 
    372                 if (v == 0) {
    373                     verdict = 0;
    374                 } else if (v != TEST_SKIP_CODE && verdict != 0) {
    375                     verdict = 1;
    376                 }
    377 
    378                 finalize(v != 0);
    379 
    380                 if (all_tests[i].subtest)
    381                     test_verdict(v, "%d - iteration %d",
    382                                  subtest_case_count + 1, j + 1);
    383                 else
    384                     test_verdict(v, "%d - %s - iteration %d",
    385                                  test_case_count + subtest_case_count + 1,
    386                                  test_title, j + 1);
    387                 subtest_case_count++;
    388             }
    389 
    390             if (all_tests[i].subtest) {
    391                 level -= 4;
    392                 test_adjust_streams_tap_level(level);
    393             }
    394             if (verdict == 0)
    395                 ++num_failed;
    396             if (all_tests[i].num == -1 || all_tests[i].subtest)
    397                 test_verdict(verdict, "%d - %s", test_case_count + 1,
    398                              all_tests[i].test_case_name);
    399             test_case_count++;
    400         }
    401     }
    402     if (num_failed != 0)
    403         return EXIT_FAILURE;
    404     return EXIT_SUCCESS;
    405 }
    406 
    407 /*
    408  * Glue an array of strings together and return it as an allocated string.
    409  * Optionally return the whole length of this string in |out_len|
    410  */
    411 char *glue_strings(const char *list[], size_t *out_len)
    412 {
    413     size_t len = 0;
    414     char *p, *ret;
    415     int i;
    416 
    417     for (i = 0; list[i] != NULL; i++)
    418         len += strlen(list[i]);
    419 
    420     if (out_len != NULL)
    421         *out_len = len;
    422 
    423     if (!TEST_ptr(ret = p = OPENSSL_malloc(len + 1)))
    424         return NULL;
    425 
    426     for (i = 0; list[i] != NULL; i++)
    427         p += strlen(strcpy(p, list[i]));
    428 
    429     return ret;
    430 }
    431 
    432 char *test_mk_file_path(const char *dir, const char *file)
    433 {
    434 # ifndef OPENSSL_SYS_VMS
    435     const char *sep = "/";
    436 # else
    437     const char *sep = "";
    438     char *dir_end;
    439     char dir_end_sep;
    440 # endif
    441     size_t dirlen = dir != NULL ? strlen(dir) : 0;
    442     size_t len = dirlen + strlen(sep) + strlen(file) + 1;
    443     char *full_file = OPENSSL_zalloc(len);
    444 
    445     if (full_file != NULL) {
    446         if (dir != NULL && dirlen > 0) {
    447             OPENSSL_strlcpy(full_file, dir, len);
    448 # ifdef OPENSSL_SYS_VMS
    449             /*
    450              * If |file| contains a directory spec, we need to do some
    451              * careful merging.
    452              * "vol:[dir.dir]" + "[.certs]sm2-root.crt" should become
    453              * "vol:[dir.dir.certs]sm2-root.crt"
    454              */
    455             dir_end = &full_file[strlen(full_file) - 1];
    456             dir_end_sep = *dir_end;
    457             if ((dir_end_sep == ']' || dir_end_sep == '>')
    458                 && (file[0] == '[' || file[0] == '<')) {
    459                 file++;
    460                 if (file[0] == '.')
    461                     *dir_end = '\0';
    462                 else
    463                     *dir_end = '.';
    464             }
    465 #else
    466             OPENSSL_strlcat(full_file, sep, len);
    467 #endif
    468         }
    469         OPENSSL_strlcat(full_file, file, len);
    470     }
    471 
    472     return full_file;
    473 }
    474