lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | /* Copyright 2000-2004 Ryan Bloom
|
| 2 | *
|
| 3 | * Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 | * you may not use this file except in compliance with the License.
|
| 5 | * You may obtain a copy of the License at
|
| 6 | *
|
| 7 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 8 | *
|
| 9 | * Unless required by applicable law or agreed to in writing, software
|
| 10 | * distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 | * See the License for the specific language governing permissions and
|
| 13 | * limitations under the License.
|
| 14 | *
|
| 15 | * Portions of this file were taken from testall.c in the APR test suite,
|
| 16 | * written by members of the Apache Software Foundation.
|
| 17 | */
|
| 18 |
|
| 19 | #include "abts.h"
|
| 20 | #include "abts_tests.h"
|
| 21 | #include "testutil.h"
|
| 22 |
|
| 23 | #define ABTS_STAT_SIZE 6
|
| 24 | static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'};
|
| 25 | static int curr_char;
|
| 26 | static int verbose = 1;
|
| 27 | static int exclude = 0;
|
| 28 | static int quiet = 0;
|
| 29 | static int list_tests = 0;
|
| 30 |
|
| 31 | const char **testlist = NULL;
|
| 32 |
|
| 33 | static int find_test_name(const char *testname) {
|
| 34 | int i;
|
| 35 | for (i = 0; testlist[i] != NULL; i++) {
|
| 36 | if (!strcmp(testlist[i], testname)) {
|
| 37 | return 1;
|
| 38 | }
|
| 39 | }
|
| 40 | return 0;
|
| 41 | }
|
| 42 |
|
| 43 | /* Determine if the test should be run at all */
|
| 44 | static int should_test_run(const char *testname) {
|
| 45 | int found = 0;
|
| 46 | if (list_tests == 1) {
|
| 47 | return 0;
|
| 48 | }
|
| 49 | if (testlist == NULL) {
|
| 50 | return 1;
|
| 51 | }
|
| 52 | found = find_test_name(testname);
|
| 53 | if ((found && !exclude) || (!found && exclude)) {
|
| 54 | return 1;
|
| 55 | }
|
| 56 | return 0;
|
| 57 | }
|
| 58 |
|
| 59 | static void reset_status(void)
|
| 60 | {
|
| 61 | curr_char = 0;
|
| 62 | }
|
| 63 |
|
| 64 | static void update_status(void)
|
| 65 | {
|
| 66 | if (!quiet) {
|
| 67 | curr_char = (curr_char + 1) % ABTS_STAT_SIZE;
|
| 68 | fprintf(stdout, "\b%c", status[curr_char]);
|
| 69 | fflush(stdout);
|
| 70 | }
|
| 71 | }
|
| 72 |
|
| 73 | static void end_suite(abts_suite *suite)
|
| 74 | {
|
| 75 | if (suite != NULL) {
|
| 76 | sub_suite *last = suite->tail;
|
| 77 | if (!quiet) {
|
| 78 | fprintf(stdout, "\b");
|
| 79 | fflush(stdout);
|
| 80 | }
|
| 81 | if (last->failed == 0) {
|
| 82 | fprintf(stdout, "SUCCESS\n");
|
| 83 | fflush(stdout);
|
| 84 | }
|
| 85 | else {
|
| 86 | fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test);
|
| 87 | fflush(stdout);
|
| 88 | }
|
| 89 | }
|
| 90 | }
|
| 91 |
|
| 92 | abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full)
|
| 93 | {
|
| 94 | sub_suite *subsuite;
|
| 95 | char *p;
|
| 96 | const char *suite_name;
|
| 97 | curr_char = 0;
|
| 98 |
|
| 99 | /* Only end the suite if we actually ran it */
|
| 100 | if (suite && suite->tail &&!suite->tail->not_run) {
|
| 101 | end_suite(suite);
|
| 102 | }
|
| 103 |
|
| 104 | subsuite = malloc(sizeof(*subsuite));
|
| 105 | subsuite->num_test = 0;
|
| 106 | subsuite->failed = 0;
|
| 107 | subsuite->next = NULL;
|
| 108 | /* suite_name_full may be an absolute path depending on __FILE__
|
| 109 | * expansion */
|
| 110 | suite_name = strrchr(suite_name_full, '/');
|
| 111 | if (suite_name) {
|
| 112 | suite_name++;
|
| 113 | } else {
|
| 114 | suite_name = suite_name_full;
|
| 115 | }
|
| 116 | p = strrchr(suite_name, '.');
|
| 117 | if (p) {
|
| 118 | subsuite->name = memcpy(calloc(p - suite_name + 1, 1),
|
| 119 | suite_name, p - suite_name);
|
| 120 | }
|
| 121 | else {
|
| 122 | subsuite->name = suite_name;
|
| 123 | }
|
| 124 |
|
| 125 | if (list_tests) {
|
| 126 | fprintf(stdout, "%s\n", subsuite->name);
|
| 127 | }
|
| 128 |
|
| 129 | subsuite->not_run = 0;
|
| 130 |
|
| 131 | if (suite == NULL) {
|
| 132 | suite = malloc(sizeof(*suite));
|
| 133 | suite->head = subsuite;
|
| 134 | suite->tail = subsuite;
|
| 135 | }
|
| 136 | else {
|
| 137 | suite->tail->next = subsuite;
|
| 138 | suite->tail = subsuite;
|
| 139 | }
|
| 140 |
|
| 141 | if (!should_test_run(subsuite->name)) {
|
| 142 | subsuite->not_run = 1;
|
| 143 | return suite;
|
| 144 | }
|
| 145 |
|
| 146 | reset_status();
|
| 147 | fprintf(stdout, "%-20s: ", subsuite->name);
|
| 148 | update_status();
|
| 149 | fflush(stdout);
|
| 150 |
|
| 151 | return suite;
|
| 152 | }
|
| 153 |
|
| 154 | void abts_run_test(abts_suite *ts, test_func f, void *value)
|
| 155 | {
|
| 156 | abts_case tc;
|
| 157 | sub_suite *ss;
|
| 158 |
|
| 159 | if (!should_test_run(ts->tail->name)) {
|
| 160 | return;
|
| 161 | }
|
| 162 | ss = ts->tail;
|
| 163 |
|
| 164 | tc.failed = 0;
|
| 165 | tc.suite = ss;
|
| 166 |
|
| 167 | ss->num_test++;
|
| 168 | update_status();
|
| 169 |
|
| 170 | f(&tc, value);
|
| 171 |
|
| 172 | if (tc.failed) {
|
| 173 | ss->failed++;
|
| 174 | }
|
| 175 | }
|
| 176 |
|
| 177 | static int report(abts_suite *suite)
|
| 178 | {
|
| 179 | int count = 0;
|
| 180 | sub_suite *dptr;
|
| 181 |
|
| 182 | if (suite && suite->tail &&!suite->tail->not_run) {
|
| 183 | end_suite(suite);
|
| 184 | }
|
| 185 |
|
| 186 | for (dptr = suite->head; dptr; dptr = dptr->next) {
|
| 187 | count += dptr->failed;
|
| 188 | }
|
| 189 |
|
| 190 | if (list_tests) {
|
| 191 | return 0;
|
| 192 | }
|
| 193 |
|
| 194 | if (count == 0) {
|
| 195 | printf("All tests passed.\n");
|
| 196 | return 0;
|
| 197 | }
|
| 198 |
|
| 199 | dptr = suite->head;
|
| 200 | fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests");
|
| 201 | fprintf(stdout, "===================================================\n");
|
| 202 | while (dptr != NULL) {
|
| 203 | if (dptr->failed != 0) {
|
| 204 | float percent = ((float)dptr->failed / (float)dptr->num_test);
|
| 205 | fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name,
|
| 206 | dptr->num_test, dptr->failed, percent * 100);
|
| 207 | }
|
| 208 | dptr = dptr->next;
|
| 209 | }
|
| 210 | return 1;
|
| 211 | }
|
| 212 |
|
| 213 | void abts_log_message(const char *fmt, ...)
|
| 214 | {
|
| 215 | va_list args;
|
| 216 | update_status();
|
| 217 |
|
| 218 | if (verbose) {
|
| 219 | va_start(args, fmt);
|
| 220 | vfprintf(stderr, fmt, args);
|
| 221 | va_end(args);
|
| 222 | fprintf(stderr, "\n");
|
| 223 | fflush(stderr);
|
| 224 | }
|
| 225 | }
|
| 226 |
|
| 227 | void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno)
|
| 228 | {
|
| 229 | update_status();
|
| 230 | if (tc->failed) return;
|
| 231 |
|
| 232 | if (expected == actual) return;
|
| 233 |
|
| 234 | tc->failed = TRUE;
|
| 235 | if (verbose) {
|
| 236 | fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
|
| 237 | fflush(stderr);
|
| 238 | }
|
| 239 | }
|
| 240 |
|
| 241 | void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno)
|
| 242 | {
|
| 243 | update_status();
|
| 244 | if (tc->failed) return;
|
| 245 |
|
| 246 | if (expected != actual) return;
|
| 247 |
|
| 248 | tc->failed = TRUE;
|
| 249 | if (verbose) {
|
| 250 | fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
|
| 251 | fflush(stderr);
|
| 252 | }
|
| 253 | }
|
| 254 |
|
| 255 | void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno)
|
| 256 | {
|
| 257 | update_status();
|
| 258 | if (tc->failed) return;
|
| 259 |
|
| 260 | if (!expected && !actual) return;
|
| 261 | if (expected && actual)
|
| 262 | if (!strcmp(expected, actual)) return;
|
| 263 |
|
| 264 | tc->failed = TRUE;
|
| 265 | if (verbose) {
|
| 266 | fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
|
| 267 | fflush(stderr);
|
| 268 | }
|
| 269 | }
|
| 270 |
|
| 271 | void abts_str_notequal(abts_case *tc, const char *expected, const char *actual, int lineno)
|
| 272 | {
|
| 273 | update_status();
|
| 274 | if (tc->failed) return;
|
| 275 |
|
| 276 | if (!expected && !actual) return;
|
| 277 | if (expected && actual)
|
| 278 | if (strcmp(expected, actual) != 0) return;
|
| 279 |
|
| 280 | tc->failed = TRUE;
|
| 281 | if (verbose) {
|
| 282 | fprintf(stderr, "Line %d: expected <%s> == saw <%s>, but we expect it not equal!\n", lineno, expected, actual);
|
| 283 | fflush(stderr);
|
| 284 | }
|
| 285 | }
|
| 286 |
|
| 287 | void abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
|
| 288 | size_t n, int lineno)
|
| 289 | {
|
| 290 | update_status();
|
| 291 | if (tc->failed) return;
|
| 292 |
|
| 293 | if (!strncmp(expected, actual, n)) return;
|
| 294 |
|
| 295 | tc->failed = TRUE;
|
| 296 | if (verbose) {
|
| 297 | fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
|
| 298 | fflush(stderr);
|
| 299 | }
|
| 300 | }
|
| 301 |
|
| 302 | void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno)
|
| 303 | {
|
| 304 | update_status();
|
| 305 | if (tc->failed) return;
|
| 306 |
|
| 307 | if (ptr != NULL) return;
|
| 308 |
|
| 309 | tc->failed = TRUE;
|
| 310 | if (verbose) {
|
| 311 | fprintf(stderr, "Line %d: Expected NULL, but saw <%p>\n", lineno, ptr);
|
| 312 | fflush(stderr);
|
| 313 | }
|
| 314 | }
|
| 315 |
|
| 316 | void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno)
|
| 317 | {
|
| 318 | update_status();
|
| 319 | if (tc->failed) return;
|
| 320 |
|
| 321 | if (expected == actual) return;
|
| 322 |
|
| 323 | tc->failed = TRUE;
|
| 324 | if (verbose) {
|
| 325 | fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual);
|
| 326 | fflush(stderr);
|
| 327 | }
|
| 328 | }
|
| 329 |
|
| 330 | void abts_fail(abts_case *tc, const char *message, int lineno)
|
| 331 | {
|
| 332 | update_status();
|
| 333 | if (tc->failed) return;
|
| 334 |
|
| 335 | tc->failed = TRUE;
|
| 336 | if (verbose) {
|
| 337 | fprintf(stderr, "Line %d: %s\n", lineno, message);
|
| 338 | fflush(stderr);
|
| 339 | }
|
| 340 | }
|
| 341 |
|
| 342 | void abts_assert(abts_case *tc, const char *message, int condition, int lineno)
|
| 343 | {
|
| 344 | update_status();
|
| 345 | if (tc->failed) return;
|
| 346 |
|
| 347 | if (condition) return;
|
| 348 |
|
| 349 | tc->failed = TRUE;
|
| 350 | if (verbose) {
|
| 351 | fprintf(stderr, "Line %d: %s\n", lineno, message);
|
| 352 | fflush(stderr);
|
| 353 | }
|
| 354 | }
|
| 355 |
|
| 356 | void abts_true(abts_case *tc, int condition, int lineno)
|
| 357 | {
|
| 358 | update_status();
|
| 359 | if (tc->failed) return;
|
| 360 |
|
| 361 | if (condition) return;
|
| 362 |
|
| 363 | tc->failed = TRUE;
|
| 364 | if (verbose) {
|
| 365 | fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno);
|
| 366 | fflush(stderr);
|
| 367 | }
|
| 368 | }
|
| 369 |
|
| 370 | void abts_not_impl(abts_case *tc, const char *message, int lineno)
|
| 371 | {
|
| 372 | update_status();
|
| 373 |
|
| 374 | tc->suite->not_impl++;
|
| 375 | if (verbose) {
|
| 376 | fprintf(stderr, "Line %d: %s\n", lineno, message);
|
| 377 | fflush(stderr);
|
| 378 | }
|
| 379 | }
|
| 380 |
|
| 381 | int main(int argc, const char *const argv[]) {
|
| 382 | int i;
|
| 383 | int rv;
|
| 384 | int list_provided = 0;
|
| 385 | abts_suite *suite = NULL;
|
| 386 |
|
| 387 | for (i = 1; i < argc; i++) {
|
| 388 | if (!strcmp(argv[i], "-v")) {
|
| 389 | verbose = 1;
|
| 390 | continue;
|
| 391 | }
|
| 392 | if (!strcmp(argv[i], "-x")) {
|
| 393 | exclude = 1;
|
| 394 | continue;
|
| 395 | }
|
| 396 | if (!strcmp(argv[i], "-l")) {
|
| 397 | list_tests = 1;
|
| 398 | continue;
|
| 399 | }
|
| 400 | if (!strcmp(argv[i], "-q")) {
|
| 401 | quiet = 1;
|
| 402 | continue;
|
| 403 | }
|
| 404 | if (argv[i][0] == '-') {
|
| 405 | fprintf(stderr, "Invalid option: `%s'\n", argv[i]);
|
| 406 | exit(1);
|
| 407 | }
|
| 408 | list_provided = 1;
|
| 409 | }
|
| 410 |
|
| 411 | if (list_provided) {
|
| 412 | /* Waste a little space here, because it is easier than counting the
|
| 413 | * number of tests listed. Besides it is at most three char *.
|
| 414 | */
|
| 415 | testlist = calloc(argc + 1, sizeof(char *));
|
| 416 | for (i = 1; i < argc; i++) {
|
| 417 | testlist[i - 1] = argv[i];
|
| 418 | }
|
| 419 | }
|
| 420 |
|
| 421 | initialize();
|
| 422 |
|
| 423 | printf("sizeof alltests is: %d\n", (int)(sizeof(alltests) / sizeof(struct testlist *)));
|
| 424 |
|
| 425 | for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) {
|
| 426 | suite = alltests[i].func(suite);
|
| 427 | }
|
| 428 |
|
| 429 | rv = report(suite);
|
| 430 |
|
| 431 | return rv;
|
| 432 | }
|
| 433 |
|