#include #include #include #include namespace fuc2 { Options parse_options(int argc, char* argv[]) { Options result; int opt = 0; while((opt = getopt(argc, argv, "fvm:")) != -1) { switch(opt) { case 'f': result.fail_fast = true; break; case 'v': result.verbose = true; break; case 'm': result.matching = std::string(optarg); break; } } return result; } int run(const Set& test_set, const Options& cli_opts, bool gave_opts) { int fail_count = 0; std::vector errors; std::string file_name = test_set.location.file_name(); Options opts = gave_opts ? cli_opts : test_set.options; if(opts.disabled) { fmt::println("! DISABLED: {}", file_name); return 0; } if(opts.verbose) { fmt::println("################# {} \"{}\" ###############", file_name, test_set.name); } else { fmt::println("> {} \"{}\"", file_name, test_set.name); } for(const auto& [name, test] : test_set.tests) { bool did_fail = false; if(opts.verbose) fmt::println("----------- START {}", name); try { test(); } catch(const std::exception& e) { fail_count++; did_fail = true; fmt::println("🚨 FAIL! {}", e.what()); errors.push_back(e.what()); if(opts.fail_fast) { fmt::println("FAIL FAST (-f) SET, STOPPING"); break; } } std::string pass_fail = did_fail ? "🔴" : "🟢"; fmt::println("{} {}:{}", pass_fail, file_name, name); if(opts.verbose) fmt::println("=========="); } if(fail_count > 0) { fmt::println("🚨🚨🚨🚨🚨 FAIL COUNT: {} in {}", fail_count, file_name); if(opts.verbose) { for(auto& msg : errors) { fmt::println("---------\n{}", msg); } } } else { fmt::println("👍 ALL PASS: {}", file_name); } return fail_count; } int run_tests(const std::vector& tests, int argc, char* argv[]) { int fail_count = 0; auto opts = parse_options(argc, argv); for(auto& test : tests) { // skip everything except ones matching the name if(!test.name.contains(opts.matching)) { continue; } fail_count += run(test, opts, argc > 1); if(opts.fail_fast && fail_count > 0) { fmt::println("FAIL FAST! Aborting early."); break; } } return fail_count; } }