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 = malloc(sizeof(*tc)); 163 tc->failed = 0; 164 tc->suite = ss; 165 166 ss->num_test++; 167 update_status(); 168 169 f(tc, value); 170 171 if (tc->failed) { 172 ss->failed++; 173 } 174 free(tc); 175} 176 177static 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 213void 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 227void 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 241void 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 255void 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 both are NULL, match is good */ 261 if (!expected && !actual) return; 262 if (expected && actual) 263 if (!strcmp(expected, actual)) return; 264 265 tc->failed = TRUE; 266 if (verbose) { 267 fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); 268 fflush(stderr); 269 } 270} 271 272void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, 273 size_t n, int lineno) 274{ 275 update_status(); 276 if (tc->failed) return; 277 278 if (!strncmp(expected, actual, n)) return; 279 280 tc->failed = TRUE; 281 if (verbose) { 282 fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); 283 fflush(stderr); 284 } 285} 286 287void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno) 288{ 289 update_status(); 290 if (tc->failed) return; 291 292 if (ptr != NULL) return; 293 294 tc->failed = TRUE; 295 if (verbose) { 296 fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno); 297 fflush(stderr); 298 } 299} 300 301void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno) 302{ 303 update_status(); 304 if (tc->failed) return; 305 306 if (expected == actual) return; 307 308 tc->failed = TRUE; 309 if (verbose) { 310 fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual); 311 fflush(stderr); 312 } 313} 314 315void abts_fail(abts_case *tc, const char *message, int lineno) 316{ 317 update_status(); 318 if (tc->failed) return; 319 320 tc->failed = TRUE; 321 if (verbose) { 322 fprintf(stderr, "Line %d: %s\n", lineno, message); 323 fflush(stderr); 324 } 325} 326 327void abts_assert(abts_case *tc, const char *message, int condition, int lineno) 328{ 329 update_status(); 330 if (tc->failed) return; 331 332 if (condition) return; 333 334 tc->failed = TRUE; 335 if (verbose) { 336 fprintf(stderr, "Line %d: %s\n", lineno, message); 337 fflush(stderr); 338 } 339} 340 341void abts_true(abts_case *tc, int condition, int lineno) 342{ 343 update_status(); 344 if (tc->failed) return; 345 346 if (condition) return; 347 348 tc->failed = TRUE; 349 if (verbose) { 350 fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno); 351 fflush(stderr); 352 } 353} 354 355void abts_not_impl(abts_case *tc, const char *message, int lineno) 356{ 357 update_status(); 358 359 tc->suite->not_impl++; 360 if (verbose) { 361 fprintf(stderr, "Line %d: %s\n", lineno, message); 362 fflush(stderr); 363 } 364} 365 366int main(int argc, const char *const argv[]) { 367 int i; 368 int rv; 369 int list_provided = 0; 370 abts_suite *suite = NULL; 371 372 initialize(); 373 374 quiet = !isatty(STDOUT_FILENO); 375 376 for (i = 1; i < argc; i++) { 377 if (!strcmp(argv[i], "-v")) { 378 verbose = 1; 379 continue; 380 } 381 if (!strcmp(argv[i], "-x")) { 382 exclude = 1; 383 continue; 384 } 385 if (!strcmp(argv[i], "-l")) { 386 list_tests = 1; 387 continue; 388 } 389 if (!strcmp(argv[i], "-q")) { 390 quiet = 1; 391 continue; 392 } 393 if (argv[i][0] == '-') { 394 fprintf(stderr, "Invalid option: `%s'\n", argv[i]); 395 exit(1); 396 } 397 list_provided = 1; 398 } 399 400 if (list_provided) { 401 /* Waste a little space here, because it is easier than counting the 402 * number of tests listed. Besides it is at most three char *. 403 */ 404 testlist = calloc(argc + 1, sizeof(char *)); 405 for (i = 1; i < argc; i++) { 406 testlist[i - 1] = argv[i]; 407 } 408 } 409 410 for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) { 411 suite = alltests[i].func(suite); 412 apr_pool_clear(p); 413 } 414 415 rv = report(suite); 416 return rv; 417} 418 419