LCOV - code coverage report
Current view: top level - spdk/lib/ut - ut.c (source / functions) Hit Total Coverage
Test: Combined Lines: 45 120 37.5 %
Date: 2024-07-15 22:18:41 Functions: 3 5 60.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 30 122 24.6 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2023 Intel Corporation. All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "spdk/stdinc.h"
       6                 :            : #include "spdk/util.h"
       7                 :            : #include "spdk_internal/cunit.h"
       8                 :            : 
       9                 :            : enum ut_action {
      10                 :            :         UT_ACTION_RUN_TESTS,
      11                 :            :         UT_ACTION_PRINT_HELP,
      12                 :            :         UT_ACTION_LIST_TESTS,
      13                 :            : };
      14                 :            : 
      15                 :            : struct ut_config {
      16                 :            :         const char                      *app;
      17                 :            :         const char                      *test;
      18                 :            :         const char                      *suite;
      19                 :            :         enum ut_action                  action;
      20                 :            :         const struct spdk_ut_opts       *opts;
      21                 :            : };
      22                 :            : 
      23                 :            : #define OPTION_STRING "hls:t:"
      24                 :            : 
      25                 :            : static const struct option g_ut_options[] = {
      26                 :            : #define OPTION_TEST_CASE 't'
      27                 :            :         {"test", required_argument, NULL, OPTION_TEST_CASE},
      28                 :            : #define OPTION_TEST_SUITE 's'
      29                 :            :         {"suite", required_argument, NULL, OPTION_TEST_SUITE},
      30                 :            : #define OPTION_LIST 'l'
      31                 :            :         {"list", no_argument, NULL, OPTION_LIST},
      32                 :            : #define OPTION_HELP 'h'
      33                 :            :         {"help", no_argument, NULL, OPTION_HELP},
      34                 :            :         {},
      35                 :            : };
      36                 :            : 
      37                 :            : static void
      38                 :          0 : usage(struct ut_config *config)
      39                 :            : {
      40                 :          0 :         const struct spdk_ut_opts *opts = config->opts;
      41                 :            : 
      42         [ #  # ]:          0 :         printf("Usage: %s [OPTIONS]\n", config->app);
      43         [ #  # ]:          0 :         printf("  -t, --test                       run single test case\n");
      44         [ #  # ]:          0 :         printf("  -s, --suite                      run all tests in a given suite\n");
      45         [ #  # ]:          0 :         printf("  -l, --list                       list registered test suites and test cases\n");
      46         [ #  # ]:          0 :         printf("  -h, --help                       print this help\n");
      47                 :            : 
      48   [ #  #  #  # ]:          0 :         if (opts != NULL && opts->usage_cb_fn != NULL) {
      49                 :          0 :                 opts->usage_cb_fn(opts->cb_arg);
      50                 :            :         }
      51                 :          0 : }
      52                 :            : 
      53                 :            : static int
      54                 :        381 : parse_args(int argc, char **argv, struct ut_config *config)
      55                 :            : {
      56                 :        381 :         const struct spdk_ut_opts *opts = config->opts;
      57                 :            : #define MAX_OPTSTRING_LEN 4096
      58                 :        381 :         char optstring[MAX_OPTSTRING_LEN] = {};
      59                 :            : #define MAX_OPT_COUNT 128
      60                 :        381 :         struct option options[MAX_OPT_COUNT] = {};
      61                 :            :         size_t optlen;
      62                 :            :         int op, rc;
      63                 :            : 
      64                 :            :         /* Run the tests by default */
      65                 :        381 :         config->action = UT_ACTION_RUN_TESTS;
      66                 :        381 :         config->app = argv[0];
      67                 :            : 
      68   [ +  +  +  - ]:        381 :         if (opts != NULL && opts->opts != NULL) {
      69                 :          1 :                 optlen = SPDK_COUNTOF(g_ut_options) + opts->optlen;
      70         [ -  + ]:          1 :                 if (optlen > MAX_OPT_COUNT) {
      71   [ #  #  #  # ]:          0 :                         fprintf(stderr, "%s: unsupported number of options: %zu\n",
      72                 :            :                                 config->app, optlen);
      73                 :          0 :                         return -EINVAL;
      74                 :            :                 }
      75                 :            : 
      76   [ -  +  -  + ]:          1 :                 memcpy(&options[0], opts->opts, sizeof(*opts->opts) * opts->optlen);
      77   [ -  +  -  + ]:          1 :                 memcpy(&options[opts->optlen], g_ut_options, sizeof(g_ut_options));
      78                 :            : 
      79         [ #  # ]:          0 :                 rc = snprintf(optstring, MAX_OPTSTRING_LEN, "%s%s", OPTION_STRING,
      80         [ -  + ]:          1 :                               opts->optstring);
      81   [ +  -  -  + ]:          1 :                 if (rc < 0 || rc >= MAX_OPTSTRING_LEN) {
      82   [ #  #  #  # ]:          0 :                         fprintf(stderr, "%s: bad optstring\n", config->app);
      83                 :          0 :                         return -EINVAL;
      84                 :            :                 }
      85                 :            :         } else {
      86         [ -  + ]:        380 :                 snprintf(optstring, sizeof(optstring), "%s", OPTION_STRING);
      87                 :        380 :                 memcpy(options, g_ut_options, sizeof(g_ut_options));
      88                 :            :         }
      89                 :            : 
      90   [ -  +  -  +  :        383 :         while ((op = getopt_long(argc, argv, optstring, options, NULL)) != -1) {
                   +  + ]
      91   [ -  -  -  -  :          2 :                 switch (op) {
                   -  + ]
      92                 :          0 :                 case OPTION_TEST_CASE:
      93                 :          0 :                         config->test = optarg;
      94                 :          0 :                         break;
      95                 :          0 :                 case OPTION_TEST_SUITE:
      96                 :          0 :                         config->suite = optarg;
      97                 :          0 :                         break;
      98                 :          0 :                 case OPTION_HELP:
      99                 :          0 :                         config->action = UT_ACTION_PRINT_HELP;
     100                 :          0 :                         break;
     101                 :          0 :                 case OPTION_LIST:
     102                 :          0 :                         config->action = UT_ACTION_LIST_TESTS;
     103                 :          0 :                         break;
     104                 :          0 :                 case '?':
     105                 :          0 :                         return -EINVAL;
     106                 :          2 :                 default:
     107   [ +  -  +  - ]:          2 :                         if (opts != NULL && opts->option_cb_fn != NULL) {
     108                 :          2 :                                 rc = opts->option_cb_fn(op, optarg, opts->cb_arg);
     109         [ -  + ]:          2 :                                 if (rc != 0) {
     110                 :          0 :                                         return rc;
     111                 :            :                                 }
     112                 :            :                         } else {
     113                 :          0 :                                 return -EINVAL;
     114                 :            :                         }
     115                 :            :                 }
     116                 :            :         }
     117                 :            : 
     118                 :        381 :         return 0;
     119                 :            : }
     120                 :            : 
     121                 :            : static int
     122                 :        381 : run_tests(const struct ut_config *config)
     123                 :            : {
     124                 :        381 :         CU_pSuite suite = NULL;
     125                 :        381 :         CU_pTest test = NULL;
     126                 :            : 
     127         [ -  + ]:        381 :         if (config->suite != NULL) {
     128                 :          0 :                 suite = CU_get_suite(config->suite);
     129         [ #  # ]:          0 :                 if (suite == NULL) {
     130   [ #  #  #  # ]:          0 :                         fprintf(stderr, "%s: invalid test suite: '%s'\n",
     131         [ #  # ]:          0 :                                 config->app, config->suite);
     132                 :          0 :                         return 1;
     133                 :            :                 }
     134                 :            :         }
     135                 :            : 
     136         [ -  + ]:        381 :         if (config->test != NULL) {
     137         [ #  # ]:          0 :                 if (suite == NULL) {
     138                 :            :                         /* Allow users to skip test suite if there's only a single test suite
     139                 :            :                          * registered (CUnit starts indexing from 1). */
     140         [ #  # ]:          0 :                         if (CU_get_suite_at_pos(2) != NULL) {
     141   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "%s: there are multiple test suites registered, "
     142         [ #  # ]:          0 :                                         "select one using the -s option\n", config->app);
     143                 :          0 :                                 return 1;
     144                 :            :                         }
     145                 :            : 
     146                 :          0 :                         suite = CU_get_suite_at_pos(1);
     147         [ #  # ]:          0 :                         if (suite == NULL) {
     148   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "%s: there are no tests registered\n", config->app);
     149                 :          0 :                                 return 1;
     150                 :            :                         }
     151                 :            :                 }
     152                 :            : 
     153                 :          0 :                 test = CU_get_test(suite, config->test);
     154         [ #  # ]:          0 :                 if (test == NULL) {
     155   [ #  #  #  # ]:          0 :                         fprintf(stderr, "%s: invalid test case: '%s'\n", config->app, config->test);
     156                 :          0 :                         return 1;
     157                 :            :                 }
     158                 :            :         }
     159                 :            : 
     160                 :        381 :         CU_set_error_action(CUEA_ABORT);
     161                 :        381 :         CU_basic_set_mode(CU_BRM_VERBOSE);
     162                 :            : 
     163                 :            :         /* Either run a single test, all tests in a given test suite, or all registered tests */
     164         [ -  + ]:        381 :         if (test != NULL) {
     165                 :          0 :                 CU_basic_run_test(suite, test);
     166         [ -  + ]:        381 :         } else if (suite != NULL) {
     167                 :          0 :                 CU_basic_run_suite(suite);
     168                 :            :         } else {
     169                 :        381 :                 CU_basic_run_tests();
     170                 :            :         }
     171                 :            : 
     172                 :        381 :         return CU_get_number_of_failures();
     173                 :            : }
     174                 :            : 
     175                 :            : static void
     176                 :          0 : list_tests(void)
     177                 :            : {
     178                 :            :         CU_pSuite suite;
     179                 :            :         CU_pTest test;
     180                 :            :         int sid, tid;
     181                 :            : 
     182                 :          0 :         for (sid = 1;; ++sid) {
     183                 :          0 :                 suite = CU_get_suite_at_pos(sid);
     184         [ #  # ]:          0 :                 if (suite == NULL) {
     185                 :          0 :                         break;
     186                 :            :                 }
     187                 :            : 
     188         [ #  # ]:          0 :                 printf("%s:\n", suite->pName);
     189                 :          0 :                 for (tid = 1;; ++tid) {
     190                 :          0 :                         test = CU_get_test_at_pos(suite, tid);
     191         [ #  # ]:          0 :                         if (test == NULL) {
     192                 :          0 :                                 break;
     193                 :            :                         }
     194                 :            : 
     195         [ #  # ]:          0 :                         printf("  %s\n", test->pName);
     196                 :            :                 }
     197                 :            :         }
     198                 :          0 : }
     199                 :            : 
     200                 :            : int
     201                 :        381 : spdk_ut_run_tests(int argc, char **argv, const struct spdk_ut_opts *opts)
     202                 :            : {
     203                 :        381 :         struct ut_config config = {.opts = opts};
     204                 :            :         int rc;
     205                 :            : 
     206                 :        381 :         rc = parse_args(argc, argv, &config);
     207         [ -  + ]:        381 :         if (rc != 0) {
     208                 :          0 :                 usage(&config);
     209                 :          0 :                 return 1;
     210                 :            :         }
     211                 :            : 
     212   [ -  +  -  - ]:        381 :         switch (config.action) {
     213                 :          0 :         case UT_ACTION_PRINT_HELP:
     214                 :          0 :                 usage(&config);
     215                 :          0 :                 break;
     216                 :        381 :         case UT_ACTION_RUN_TESTS:
     217   [ +  +  +  - ]:        381 :                 if (opts != NULL && opts->init_cb_fn != NULL) {
     218                 :          1 :                         rc = opts->init_cb_fn(opts->cb_arg);
     219         [ -  + ]:          1 :                         if (rc != 0) {
     220                 :          0 :                                 usage(&config);
     221                 :          0 :                                 return 1;
     222                 :            :                         }
     223                 :            :                 }
     224                 :            : 
     225                 :        381 :                 rc = run_tests(&config);
     226                 :        381 :                 break;
     227                 :          0 :         case UT_ACTION_LIST_TESTS:
     228                 :          0 :                 list_tests();
     229                 :          0 :                 break;
     230                 :          0 :         default:
     231                 :          0 :                 assert(0);
     232                 :            :         }
     233                 :            : 
     234                 :        381 :         return rc;
     235                 :            : }

Generated by: LCOV version 1.14