Git fork
at reftables-rust 456 lines 9.2 kB view raw
1#define DISABLE_SIGN_COMPARE_WARNINGS 2 3#include "test-lib.h" 4 5enum result { 6 RESULT_NONE, 7 RESULT_FAILURE, 8 RESULT_SKIP, 9 RESULT_SUCCESS, 10 RESULT_TODO 11}; 12 13static struct { 14 enum result result; 15 int count; 16 unsigned failed :1; 17 unsigned lazy_plan :1; 18 unsigned running :1; 19 unsigned skip_all :1; 20 unsigned todo :1; 21 char location[100]; 22 char description[100]; 23} ctx = { 24 .lazy_plan = 1, 25 .result = RESULT_NONE, 26}; 27 28/* 29 * Visual C interpolates the absolute Windows path for `__FILE__`, 30 * but we want to see relative paths, as verified by t0080. 31 * There are other compilers that do the same, and are not for 32 * Windows. 33 */ 34#include "dir.h" 35 36static const char *make_relative(const char *location) 37{ 38 static char prefix[] = __FILE__, buf[PATH_MAX], *p; 39 static size_t prefix_len; 40 static int need_bs_to_fs = -1; 41 42 /* one-time preparation */ 43 if (need_bs_to_fs < 0) { 44 size_t len = strlen(prefix); 45 char needle[] = "t\\unit-tests\\test-lib.c"; 46 size_t needle_len = strlen(needle); 47 48 if (len < needle_len) 49 die("unexpected prefix '%s'", prefix); 50 51 /* 52 * The path could be relative (t/unit-tests/test-lib.c) 53 * or full (/home/user/git/t/unit-tests/test-lib.c). 54 * Check the slash between "t" and "unit-tests". 55 */ 56 prefix_len = len - needle_len; 57 if (prefix[prefix_len + 1] == '/') { 58 /* Oh, we're not Windows */ 59 for (size_t i = 0; i < needle_len; i++) 60 if (needle[i] == '\\') 61 needle[i] = '/'; 62 need_bs_to_fs = 0; 63 } else { 64 need_bs_to_fs = 1; 65 } 66 67 /* 68 * prefix_len == 0 if the compiler gives paths relative 69 * to the root of the working tree. Otherwise, we want 70 * to see that we did find the needle[] at a directory 71 * boundary. Again we rely on that needle[] begins with 72 * "t" followed by the directory separator. 73 */ 74 if (fspathcmp(needle, prefix + prefix_len) || 75 (prefix_len && prefix[prefix_len - 1] != needle[1])) 76 die("unexpected suffix of '%s'", prefix); 77 } 78 79 /* 80 * Does it not start with the expected prefix? 81 * Return it as-is without making it worse. 82 */ 83 if (prefix_len && fspathncmp(location, prefix, prefix_len)) 84 return location; 85 86 /* 87 * If we do not need to munge directory separator, we can return 88 * the substring at the tail of the location. 89 */ 90 if (!need_bs_to_fs) 91 return location + prefix_len; 92 93 /* convert backslashes to forward slashes */ 94 strlcpy(buf, location + prefix_len, sizeof(buf)); 95 for (p = buf; *p; p++) 96 if (*p == '\\') 97 *p = '/'; 98 return buf; 99} 100 101static void msg_with_prefix(const char *prefix, const char *format, va_list ap) 102{ 103 fflush(stderr); 104 if (prefix) 105 fprintf(stdout, "%s", prefix); 106 vprintf(format, ap); /* TODO: handle newlines */ 107 putc('\n', stdout); 108 fflush(stdout); 109} 110 111void test_msg(const char *format, ...) 112{ 113 va_list ap; 114 115 va_start(ap, format); 116 msg_with_prefix("# ", format, ap); 117 va_end(ap); 118} 119 120void test_plan(int count) 121{ 122 assert(!ctx.running); 123 124 fflush(stderr); 125 printf("1..%d\n", count); 126 fflush(stdout); 127 ctx.lazy_plan = 0; 128} 129 130int test_done(void) 131{ 132 if (ctx.running && ctx.location[0] && ctx.description[0]) 133 test__run_end(1, ctx.location, "%s", ctx.description); 134 assert(!ctx.running); 135 136 if (ctx.lazy_plan) 137 test_plan(ctx.count); 138 139 return ctx.failed; 140} 141 142void test_skip(const char *format, ...) 143{ 144 va_list ap; 145 146 assert(ctx.running); 147 148 ctx.result = RESULT_SKIP; 149 va_start(ap, format); 150 if (format) 151 msg_with_prefix("# skipping test - ", format, ap); 152 va_end(ap); 153} 154 155void test_skip_all(const char *format, ...) 156{ 157 va_list ap; 158 const char *prefix; 159 160 if (!ctx.count && ctx.lazy_plan) { 161 /* We have not printed a test plan yet */ 162 prefix = "1..0 # SKIP "; 163 ctx.lazy_plan = 0; 164 } else { 165 /* We have already printed a test plan */ 166 prefix = "Bail out! # "; 167 ctx.failed = 1; 168 } 169 ctx.skip_all = 1; 170 ctx.result = RESULT_SKIP; 171 va_start(ap, format); 172 msg_with_prefix(prefix, format, ap); 173 va_end(ap); 174} 175 176void test__run_describe(const char *location, const char *format, ...) 177{ 178 va_list ap; 179 int len; 180 181 assert(ctx.running); 182 assert(!ctx.location[0]); 183 assert(!ctx.description[0]); 184 185 xsnprintf(ctx.location, sizeof(ctx.location), "%s", 186 make_relative(location)); 187 188 va_start(ap, format); 189 len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap); 190 va_end(ap); 191 if (len < 0) 192 die("unable to format message: %s", format); 193 if (len >= sizeof(ctx.description)) 194 BUG("ctx.description too small to format %s", format); 195} 196 197int test__run_begin(void) 198{ 199 if (ctx.running && ctx.location[0] && ctx.description[0]) 200 test__run_end(1, ctx.location, "%s", ctx.description); 201 assert(!ctx.running); 202 203 ctx.count++; 204 ctx.result = RESULT_NONE; 205 ctx.running = 1; 206 ctx.location[0] = '\0'; 207 ctx.description[0] = '\0'; 208 209 return ctx.skip_all; 210} 211 212static void print_description(const char *format, va_list ap) 213{ 214 if (format) { 215 fputs(" - ", stdout); 216 vprintf(format, ap); 217 } 218} 219 220int test__run_end(int was_run UNUSED, const char *location, const char *format, ...) 221{ 222 va_list ap; 223 224 assert(ctx.running); 225 assert(!ctx.todo); 226 227 fflush(stderr); 228 va_start(ap, format); 229 if (!ctx.skip_all) { 230 switch (ctx.result) { 231 case RESULT_SUCCESS: 232 printf("ok %d", ctx.count); 233 print_description(format, ap); 234 break; 235 236 case RESULT_FAILURE: 237 printf("not ok %d", ctx.count); 238 print_description(format, ap); 239 break; 240 241 case RESULT_TODO: 242 printf("not ok %d", ctx.count); 243 print_description(format, ap); 244 printf(" # TODO"); 245 break; 246 247 case RESULT_SKIP: 248 printf("ok %d", ctx.count); 249 print_description(format, ap); 250 printf(" # SKIP"); 251 break; 252 253 case RESULT_NONE: 254 test_msg("BUG: test has no checks at %s", 255 make_relative(location)); 256 printf("not ok %d", ctx.count); 257 print_description(format, ap); 258 ctx.result = RESULT_FAILURE; 259 break; 260 } 261 } 262 va_end(ap); 263 ctx.running = 0; 264 if (ctx.skip_all) 265 return 1; 266 putc('\n', stdout); 267 fflush(stdout); 268 ctx.failed |= ctx.result == RESULT_FAILURE; 269 270 return ctx.result != RESULT_FAILURE; 271} 272 273static void test_fail(void) 274{ 275 assert(ctx.result != RESULT_SKIP); 276 277 ctx.result = RESULT_FAILURE; 278} 279 280static void test_pass(void) 281{ 282 assert(ctx.result != RESULT_SKIP); 283 284 if (ctx.result == RESULT_NONE) 285 ctx.result = RESULT_SUCCESS; 286} 287 288static void test_todo(void) 289{ 290 assert(ctx.result != RESULT_SKIP); 291 292 if (ctx.result != RESULT_FAILURE) 293 ctx.result = RESULT_TODO; 294} 295 296int test_assert(const char *location, const char *check, int ok) 297{ 298 if (!ctx.running) { 299 test_msg("BUG: check outside of test at %s", 300 make_relative(location)); 301 ctx.failed = 1; 302 return 0; 303 } 304 305 if (ctx.result == RESULT_SKIP) { 306 test_msg("skipping check '%s' at %s", check, 307 make_relative(location)); 308 return 1; 309 } 310 if (!ctx.todo) { 311 if (ok) { 312 test_pass(); 313 } else { 314 test_msg("check \"%s\" failed at %s", check, 315 make_relative(location)); 316 test_fail(); 317 } 318 } 319 320 return !!ok; 321} 322 323void test__todo_begin(void) 324{ 325 assert(ctx.running); 326 assert(!ctx.todo); 327 328 ctx.todo = 1; 329} 330 331int test__todo_end(const char *location, const char *check, int res) 332{ 333 assert(ctx.running); 334 assert(ctx.todo); 335 336 ctx.todo = 0; 337 if (ctx.result == RESULT_SKIP) 338 return 1; 339 if (res) { 340 test_msg("todo check '%s' succeeded at %s", check, 341 make_relative(location)); 342 test_fail(); 343 } else { 344 test_todo(); 345 } 346 347 return !res; 348} 349 350int check_bool_loc(const char *loc, const char *check, int ok) 351{ 352 return test_assert(loc, check, ok); 353} 354 355union test__tmp test__tmp[2]; 356 357int check_pointer_eq_loc(const char *loc, const char *check, int ok, 358 const void *a, const void *b) 359{ 360 int ret = test_assert(loc, check, ok); 361 362 if (!ret) { 363 test_msg(" left: %p", a); 364 test_msg(" right: %p", b); 365 } 366 367 return ret; 368} 369 370int check_int_loc(const char *loc, const char *check, int ok, 371 intmax_t a, intmax_t b) 372{ 373 int ret = test_assert(loc, check, ok); 374 375 if (!ret) { 376 test_msg(" left: %"PRIdMAX, a); 377 test_msg(" right: %"PRIdMAX, b); 378 } 379 380 return ret; 381} 382 383int check_uint_loc(const char *loc, const char *check, int ok, 384 uintmax_t a, uintmax_t b) 385{ 386 int ret = test_assert(loc, check, ok); 387 388 if (!ret) { 389 test_msg(" left: %"PRIuMAX, a); 390 test_msg(" right: %"PRIuMAX, b); 391 } 392 393 return ret; 394} 395 396static void print_one_char(char ch, char quote) 397{ 398 if ((unsigned char)ch < 0x20u || ch == 0x7f) { 399 /* TODO: improve handling of \a, \b, \f ... */ 400 printf("\\%03o", (unsigned char)ch); 401 } else { 402 if (ch == '\\' || ch == quote) 403 putc('\\', stdout); 404 putc(ch, stdout); 405 } 406} 407 408static void print_char(const char *prefix, char ch) 409{ 410 printf("# %s: '", prefix); 411 print_one_char(ch, '\''); 412 fputs("'\n", stdout); 413} 414 415int check_char_loc(const char *loc, const char *check, int ok, char a, char b) 416{ 417 int ret = test_assert(loc, check, ok); 418 419 if (!ret) { 420 fflush(stderr); 421 print_char(" left", a); 422 print_char(" right", b); 423 fflush(stdout); 424 } 425 426 return ret; 427} 428 429static void print_str(const char *prefix, const char *str) 430{ 431 printf("# %s: ", prefix); 432 if (!str) { 433 fputs("NULL\n", stdout); 434 } else { 435 putc('"', stdout); 436 while (*str) 437 print_one_char(*str++, '"'); 438 fputs("\"\n", stdout); 439 } 440} 441 442int check_str_loc(const char *loc, const char *check, 443 const char *a, const char *b) 444{ 445 int ok = (!a && !b) || (a && b && !strcmp(a, b)); 446 int ret = test_assert(loc, check, ok); 447 448 if (!ret) { 449 fflush(stderr); 450 print_str(" left", a); 451 print_str(" right", b); 452 fflush(stdout); 453 } 454 455 return ret; 456}