Back to home page

Enduro/X

 
 

    


0001 #include <cgreen/assertions.h>
0002 #include <cgreen/mocks.h>
0003 #include <cgreen/reporter.h>
0004 #include <cgreen/suite.h>
0005 #include <cgreen/internal/runner_platform.h>
0006 #include <stdarg.h>
0007 #include <stdio.h>
0008 #include <stdlib.h>
0009 #include <string.h>
0010 #include <sys/types.h>
0011 #include <unistd.h>
0012 
0013 #include "cgreen/runner.h"
0014 
0015 #ifdef __cplusplus
0016 #include <stdexcept>
0017 
0018 namespace cgreen {
0019 #endif
0020 
0021 static const char* CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE = "CGREEN_PER_TEST_TIMEOUT";
0022 
0023 static void run_every_test(TestSuite *suite, TestReporter *reporter);
0024 static void run_named_test(TestSuite *suite, const char *name, TestReporter *reporter);
0025 
0026 static void run_test_in_the_current_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter);
0027 
0028 static int per_test_timeout_defined(void);
0029 static int per_test_timeout_value(void);
0030 static void validate_per_test_timeout_value(void);
0031 
0032 int run_test_suite(TestSuite *suite, TestReporter *reporter) {
0033     int success;
0034     if (per_test_timeout_defined()) {
0035         validate_per_test_timeout_value();
0036     }
0037 
0038     setup_reporting(reporter);
0039     run_every_test(suite, reporter);
0040     success = (reporter->failures == 0) && (reporter->exceptions==0);
0041     return success ? EXIT_SUCCESS : EXIT_FAILURE;
0042 }
0043 
0044 int run_single_test(TestSuite *suite, const char *name, TestReporter *reporter) {
0045     int success;
0046     if (per_test_timeout_defined()) {
0047         validate_per_test_timeout_value();
0048     }
0049 
0050     setup_reporting(reporter);
0051     run_named_test(suite, name, reporter);
0052     success = (reporter->failures == 0);
0053     return success ? EXIT_SUCCESS : EXIT_FAILURE;
0054 }
0055 
0056 static void run_every_test(TestSuite *suite, TestReporter *reporter) {
0057     int i;
0058 
0059     run_specified_test_if_child(suite, reporter);
0060 
0061     (*reporter->start_suite)(reporter, suite->name, count_tests(suite));
0062     for (i = 0; i < suite->size; i++) {
0063         if (suite->tests[i].type == test_function) {
0064             run_test_in_its_own_process(suite, suite->tests[i].Runnable.test, reporter);
0065         } else {
0066             (*suite->setup)();
0067             run_every_test(suite->tests[i].Runnable.suite, reporter);
0068             (*suite->teardown)();
0069         }
0070     }
0071     send_reporter_completion_notification(reporter);
0072     (*reporter->finish_suite)(reporter, suite->filename, suite->line);
0073 }
0074 
0075 static void run_named_test(TestSuite *suite, const char *name, TestReporter *reporter) {
0076     int i;
0077     (*reporter->start_suite)(reporter, suite->name, count_tests(suite));
0078     for (i = 0; i < suite->size; i++) {
0079         if (suite->tests[i].type == test_function) {
0080             if (strcmp(suite->tests[i].name, name) == 0) {
0081                 run_test_in_the_current_process(suite, suite->tests[i].Runnable.test, reporter);
0082             }
0083         } else if (has_test(suite->tests[i].Runnable.suite, name)) {
0084             (*suite->setup)();
0085             run_named_test(suite->tests[i].Runnable.suite, name, reporter);
0086             (*suite->teardown)();
0087         }
0088     }
0089     send_reporter_completion_notification(reporter);
0090     (*reporter->finish_suite)(reporter, suite->filename, suite->line);
0091 }
0092 
0093 
0094 static void run_test_in_the_current_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter) {
0095     (*reporter->start_test)(reporter, test->name);
0096     run_the_test_code(suite, test, reporter);
0097     send_reporter_completion_notification(reporter);
0098     (*reporter->finish_test)(reporter, test->filename, test->line, NULL);
0099 }
0100 
0101 static int per_test_timeout_defined() {
0102     return getenv(CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE) != NULL;
0103 }
0104 
0105 static int per_test_timeout_value() {
0106     char* timeout_string;
0107     int timeout_value;
0108 
0109     if (!per_test_timeout_defined()) {
0110         die("attempt to fetch undefined value for %s\n", CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE);
0111     }
0112 
0113     timeout_string = getenv(CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE);
0114     timeout_value = atoi(timeout_string);
0115 
0116     return timeout_value;
0117 }
0118 
0119 static void validate_per_test_timeout_value() {
0120     int timeout = per_test_timeout_value();
0121 
0122     if (timeout <= 0) {
0123         die("invalid value for %s environment variable: %d\n", CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE, timeout);
0124     }
0125 }
0126 
0127 static void run_setup_for(CgreenTest *spec) {
0128 #ifdef __cplusplus
0129     std::string message = "an exception was thrown during setup: ";
0130     try {
0131 #endif
0132         spec->context->setup();
0133 #ifdef __cplusplus
0134         return;
0135     } catch(const std::exception& exception) {
0136         message += '[';
0137         message += exception.what();
0138         message += ']';
0139     } catch(const std::exception* exception) {
0140         message += '[';
0141         message += exception->what();
0142         message += ']';
0143     } catch(const std::string& exception_message) {
0144         message += '[';
0145         message += exception_message;
0146         message += ']';
0147     } catch(const std::string *exception_message) {
0148         message += '[';
0149         message += *exception_message;
0150         message += ']';
0151     } catch(const char *exception_message) {
0152         message += '[';
0153         message += exception_message;
0154         message += ']';
0155     } catch (...) {
0156         message += "unknown exception type";
0157     }
0158     va_list no_arguments;
0159     memset(&no_arguments, 0, sizeof(va_list));
0160     TestReporter *reporter = get_test_reporter();
0161     reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments);
0162     send_reporter_exception_notification(reporter);
0163 #endif
0164 }
0165 
0166 static void run_teardown_for(CgreenTest *spec) {
0167 #ifdef __cplusplus
0168     std::string message = "an exception was thrown during teardown: ";
0169     try {
0170 #endif
0171         spec->context->teardown();
0172 #ifdef __cplusplus
0173         return;
0174     } catch(const std::exception& exception) {
0175         message += '[';
0176         message += exception.what();
0177         message += ']';
0178     } catch(const std::exception* exception) {
0179         message += '[';
0180         message += exception->what();
0181         message += ']';
0182     } catch(const std::string& exception_message) {
0183         message += '[';
0184         message += exception_message;
0185         message += ']';
0186     } catch(const std::string *exception_message) {
0187         message += '[';
0188         message += *exception_message;
0189         message += ']';
0190     } catch(const char *exception_message) {
0191         message += '[';
0192         message += exception_message;
0193         message += ']';
0194     } catch (...) {
0195         message += "unknown exception type";
0196     }
0197     va_list no_arguments;
0198     memset(&no_arguments, 0, sizeof(va_list));
0199     TestReporter *reporter = get_test_reporter();
0200     reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments);
0201     send_reporter_exception_notification(reporter);
0202 #endif
0203 }
0204 
0205 /**
0206    run()
0207    
0208    N.B. Although this is neither an API or public function, it is
0209    documented as a good place to put a breakpoint. Do not change the
0210    name or semantics of this function, it should continue to be very
0211    close to the test code. */
0212 static void run(CgreenTest *spec) {
0213 #ifdef __cplusplus
0214     std::string message = "an exception was thrown during test: ";
0215     try {
0216 #endif
0217         spec->run();
0218 #ifdef __cplusplus
0219         return;
0220     } catch(const std::exception& exception) {
0221         message += '[';
0222         message += exception.what();
0223         message += ']';
0224     } catch(const std::exception* exception) {
0225         message += '[';
0226         message += exception->what();
0227         message += ']';
0228     } catch(const std::string& exception_message) {
0229         message += '[';
0230         message += exception_message;
0231         message += ']';
0232     } catch(const std::string *exception_message) {
0233         message += '[';
0234         message += *exception_message;
0235         message += ']';
0236     } catch(const char *exception_message) {
0237         message += '[';
0238         message += exception_message;
0239         message += ']';
0240     } catch (...) {
0241         message += "unknown exception type";
0242     }
0243     va_list no_arguments;
0244     memset(&no_arguments, 0, sizeof(va_list));
0245     TestReporter *reporter = get_test_reporter();
0246     reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments);
0247     send_reporter_exception_notification(reporter);
0248 #endif
0249 }
0250 
0251 void run_the_test_code(TestSuite *suite, CgreenTest *spec, TestReporter *reporter) {
0252     significant_figures_for_assert_double_are(8);
0253     clear_mocks();
0254 
0255     if (per_test_timeout_defined()) {
0256         validate_per_test_timeout_value();
0257 
0258         die_in(per_test_timeout_value());
0259     }
0260 
0261     /* for historical reasons the suite can have a setup*/
0262     if(has_setup(suite)) {
0263         (*suite->setup)();
0264     } else {
0265         if (spec->context->setup != NULL) {
0266             run_setup_for(spec);
0267         }
0268     }
0269 
0270     run(spec);
0271     /* for historical reasons the suite can have a teardown*/
0272     if (suite->teardown != &do_nothing) {
0273         (*suite->teardown)();
0274     } else {
0275         if (spec->context->teardown != NULL) {
0276             run_teardown_for(spec);
0277         }
0278     }
0279 
0280     tally_mocks(reporter);
0281 }
0282 
0283 void die(const char *message, ...) {
0284     va_list arguments;
0285     va_start(arguments, message);
0286     vprintf(message, arguments);
0287     va_end(arguments);
0288     exit(EXIT_FAILURE);
0289 }
0290 
0291 #ifdef __cplusplus
0292 } /* namespace cgreen */
0293 #endif
0294 
0295 /* vim: set ts=4 sw=4 et cindent: */