22 inline bool validateDoctestArguments(
int argc,
char **argv) {
24 static const std::vector<std::string> valid_prefixes = {
"-?",
"--help",
"-h",
"-v",
"--version",
"-c",
"--count",
"-ltc",
"--list-test-cases",
"-lts",
"--list-test-suites",
"-lr",
"--list-reporters",
"-tc",
"--test-case",
"-tce",
25 "--test-case-exclude",
"-sf",
"--source-file",
"-sfe",
"--source-file-exclude",
"-ts",
"--test-suite",
"-tse",
"--test-suite-exclude",
"-sc",
"--subcase",
"-sce",
"--subcase-exclude",
26 "-r",
"--reporters",
"-o",
"--out",
"-ob",
"--order-by",
"-rs",
"--rand-seed",
"-f",
"--first",
"-l",
"--last",
"-aa",
"--abort-after",
"-scfl",
"--subcase-filter-levels",
28 "-dt-?",
"--dt-help",
"-dt-h",
"-dt-v",
"--dt-version",
"-dt-c",
"--dt-count",
"-dt-ltc",
"--dt-list-test-cases",
"-dt-lts",
"--dt-list-test-suites",
"-dt-lr",
"--dt-list-reporters",
29 "-dt-tc",
"--dt-test-case",
"-dt-tce",
"--dt-test-case-exclude",
"-dt-sf",
"--dt-source-file",
"-dt-sfe",
"--dt-source-file-exclude",
"-dt-ts",
"--dt-test-suite",
"-dt-tse",
30 "--dt-test-suite-exclude",
"-dt-sc",
"--dt-subcase",
"-dt-sce",
"--dt-subcase-exclude",
"-dt-r",
"--dt-reporters",
"-dt-o",
"--dt-out",
"-dt-ob",
"--dt-order-by",
"-dt-rs",
31 "--dt-rand-seed",
"-dt-f",
"--dt-first",
"-dt-l",
"--dt-last",
"-dt-aa",
"--dt-abort-after",
"-dt-scfl",
"--dt-subcase-filter-levels"};
33 auto isValidDoctestArgument = [&](
const std::string &arg) ->
bool {
35 for (
const auto &prefix: valid_prefixes) {
36 if (arg == prefix || (arg.length() > prefix.length() && arg.substr(0, prefix.length()) == prefix && arg[prefix.length()] ==
'=')) {
44 std::vector<std::string> invalid_args;
45 for (
int i = 1; i < argc; ++i) {
46 std::string arg(argv[i]);
47 if (!isValidDoctestArgument(arg)) {
48 invalid_args.push_back(arg);
53 if (!invalid_args.empty()) {
54 std::cerr <<
"WARNING: Invalid or unrecognized test arguments detected:" << std::endl;
55 for (
const auto &invalid_arg: invalid_args) {
56 std::cerr <<
" " << invalid_arg << std::endl;
58 std::cerr << std::endl;
59 std::cerr <<
"Common valid patterns:" << std::endl;
60 std::cerr <<
" -tc=\"pattern\" : Run tests matching pattern" << std::endl;
61 std::cerr <<
" --test-case=\"pattern\" : Run tests matching pattern" << std::endl;
62 std::cerr <<
" -c : Count matching tests" << std::endl;
63 std::cerr <<
" --help : Show full help" << std::endl;
64 std::cerr << std::endl;
67 for (
const auto &invalid_arg: invalid_args) {
68 if (!invalid_arg.empty() && invalid_arg[0] !=
'-') {
69 std::cerr <<
"Suggestion: Did you mean -tc=\"" << invalid_arg <<
"\" ?" << std::endl;
72 std::cerr << std::endl;
73 std::cerr <<
"Proceeding with test execution..." << std::endl;
74 std::cerr << std::endl;
92 inline bool checkTestFiltersMatchTests(
int argc,
char **argv) {
94 doctest::Context count_context;
95 count_context.applyCommandLine(argc, argv);
98 count_context.setOption(
"count",
true);
99 count_context.setOption(
"no-run",
true);
102 std::ostringstream count_output;
103 std::streambuf *orig_cout = std::cout.rdbuf();
104 std::cout.rdbuf(count_output.rdbuf());
107 int count_result = count_context.run();
110 std::cout.rdbuf(orig_cout);
113 std::string output = count_output.str();
116 if (output.find(
"unskipped test cases passing the current filters: 0") != std::string::npos || output.find(
"number of tests: 0") != std::string::npos) {
118 bool has_test_filters =
false;
119 for (
int i = 1; i < argc; ++i) {
120 std::string arg(argv[i]);
121 if (arg.find(
"-tc=") == 0 || arg.find(
"--test-case=") == 0 || arg.find(
"-ts=") == 0 || arg.find(
"--test-suite=") == 0 || arg.find(
"-sc=") == 0 || arg.find(
"--subcase=") == 0 || arg.find(
"-dt-tc=") == 0 ||
122 arg.find(
"--dt-test-case=") == 0 || arg.find(
"-dt-ts=") == 0 || arg.find(
"--dt-test-suite=") == 0 || arg.find(
"-dt-sc=") == 0 || arg.find(
"--dt-subcase=") == 0) {
123 has_test_filters =
true;
128 if (has_test_filters) {
129 std::cerr <<
"WARNING: No tests match the specified filters!" << std::endl;
130 std::cerr <<
"Your filter criteria resulted in 0 matching tests." << std::endl;
131 std::cerr <<
"Use -ltc or --list-test-cases to see available tests." << std::endl;
132 std::cerr << std::endl;
151 template<
typename ContextType = doctest::Context>
152 inline int runDoctestWithValidation(
int argc,
char **argv) {
154 validateDoctestArguments(argc, argv);
157 checkTestFiltersMatchTests(argc, argv);
161 context.applyCommandLine(argc, argv);
162 int res = context.run();
164 if (context.shouldExit()) {