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