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 : 583 : parse_args(int argc, char **argv, struct ut_config *config)
55 : : {
56 : 583 : const struct spdk_ut_opts *opts = config->opts;
57 : : #define MAX_OPTSTRING_LEN 4096
58 : 583 : char optstring[MAX_OPTSTRING_LEN] = {};
59 : : #define MAX_OPT_COUNT 128
60 : 583 : struct option options[MAX_OPT_COUNT] = {};
61 : : size_t optlen;
62 : : int op, rc;
63 : :
64 : : /* Run the tests by default */
65 : 583 : config->action = UT_ACTION_RUN_TESTS;
66 : 583 : config->app = argv[0];
67 : :
68 [ + + + - ]: 583 : 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 [ - + ]: 582 : snprintf(optstring, sizeof(optstring), "%s", OPTION_STRING);
87 : 582 : memcpy(options, g_ut_options, sizeof(g_ut_options));
88 : : }
89 : :
90 [ - + - + : 585 : 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 : 583 : return 0;
119 : : }
120 : :
121 : : static int
122 : 583 : run_tests(const struct ut_config *config)
123 : : {
124 : 583 : CU_pSuite suite = NULL;
125 : 583 : CU_pTest test = NULL;
126 : :
127 [ - + ]: 583 : 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 [ - + ]: 583 : 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 : 583 : CU_set_error_action(CUEA_ABORT);
161 : 583 : 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 [ - + ]: 583 : if (test != NULL) {
165 : 0 : CU_basic_run_test(suite, test);
166 [ - + ]: 583 : } else if (suite != NULL) {
167 : 0 : CU_basic_run_suite(suite);
168 : : } else {
169 : 583 : CU_basic_run_tests();
170 : : }
171 : :
172 : 583 : 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 : 583 : spdk_ut_run_tests(int argc, char **argv, const struct spdk_ut_opts *opts)
202 : : {
203 : 583 : struct ut_config config = {.opts = opts};
204 : : int rc;
205 : :
206 : 583 : rc = parse_args(argc, argv, &config);
207 [ - + ]: 583 : if (rc != 0) {
208 : 0 : usage(&config);
209 : 0 : return 1;
210 : : }
211 : :
212 [ - + - - ]: 583 : switch (config.action) {
213 : 0 : case UT_ACTION_PRINT_HELP:
214 : 0 : usage(&config);
215 : 0 : break;
216 : 583 : case UT_ACTION_RUN_TESTS:
217 [ + + + - ]: 583 : 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 : 583 : rc = run_tests(&config);
226 : 583 : 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 : 583 : return rc;
235 : : }
|