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