CmdLine.tests.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. // Copyright Catch2 Authors
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // https://www.boost.org/LICENSE_1_0.txt)
  5. // SPDX-License-Identifier: BSL-1.0
  6. #include <catch2/catch_config.hpp>
  7. #include <catch2/catch_approx.hpp>
  8. #include <catch2/catch_test_macros.hpp>
  9. #include <catch2/matchers/catch_matchers_string.hpp>
  10. #include <catch2/internal/catch_test_spec_parser.hpp>
  11. #include <catch2/catch_user_config.hpp>
  12. #include <catch2/catch_test_case_info.hpp>
  13. #include <catch2/internal/catch_commandline.hpp>
  14. #include <catch2/generators/catch_generators.hpp>
  15. #include <catch2/internal/catch_compiler_capabilities.hpp>
  16. namespace {
  17. auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
  18. }
  19. TEST_CASE( "Parse test names and tags", "[command-line][test-spec]" ) {
  20. using Catch::parseTestSpec;
  21. using Catch::TestSpec;
  22. auto tcA = fakeTestCase( "a" );
  23. auto tcB = fakeTestCase( "b", "[one][x]" );
  24. auto tcC = fakeTestCase( "longer name with spaces", "[two][three][.][x]" );
  25. auto tcD = fakeTestCase( "zlonger name with spacesz" );
  26. SECTION( "Empty test spec should have no filters" ) {
  27. TestSpec spec;
  28. CHECK( spec.hasFilters() == false );
  29. CHECK( spec.matches( *tcA ) == false );
  30. CHECK( spec.matches( *tcB ) == false );
  31. }
  32. SECTION( "Test spec from empty string should have no filters" ) {
  33. TestSpec spec = parseTestSpec( "" );
  34. CHECK( spec.hasFilters() == false );
  35. CHECK( spec.matches( *tcA ) == false );
  36. CHECK( spec.matches( *tcB ) == false );
  37. }
  38. SECTION( "Test spec from just a comma should have no filters" ) {
  39. TestSpec spec = parseTestSpec( "," );
  40. CHECK( spec.hasFilters() == false );
  41. CHECK( spec.matches( *tcA ) == false );
  42. CHECK( spec.matches( *tcB ) == false );
  43. }
  44. SECTION( "Test spec from name should have one filter" ) {
  45. TestSpec spec = parseTestSpec( "b" );
  46. CHECK( spec.hasFilters() == true );
  47. CHECK( spec.matches( *tcA ) == false );
  48. CHECK( spec.matches( *tcB ) == true );
  49. }
  50. SECTION( "Test spec from quoted name should have one filter" ) {
  51. TestSpec spec = parseTestSpec( "\"b\"" );
  52. CHECK( spec.hasFilters() == true );
  53. CHECK( spec.matches( *tcA ) == false );
  54. CHECK( spec.matches( *tcB ) == true );
  55. }
  56. SECTION( "Test spec from name should have one filter" ) {
  57. TestSpec spec = parseTestSpec( "b" );
  58. CHECK( spec.hasFilters() == true );
  59. CHECK( spec.matches( *tcA ) == false );
  60. CHECK( spec.matches( *tcB ) == true );
  61. CHECK( spec.matches( *tcC ) == false );
  62. }
  63. SECTION( "Wildcard at the start" ) {
  64. TestSpec spec = parseTestSpec( "*spaces" );
  65. CHECK( spec.hasFilters() == true );
  66. CHECK( spec.matches( *tcA ) == false );
  67. CHECK( spec.matches( *tcB ) == false );
  68. CHECK( spec.matches( *tcC ) == true );
  69. CHECK( spec.matches( *tcD ) == false );
  70. CHECK( parseTestSpec( "*a" ).matches( *tcA ) == true );
  71. }
  72. SECTION( "Wildcard at the end" ) {
  73. TestSpec spec = parseTestSpec( "long*" );
  74. CHECK( spec.hasFilters() == true );
  75. CHECK( spec.matches( *tcA ) == false );
  76. CHECK( spec.matches( *tcB ) == false );
  77. CHECK( spec.matches( *tcC ) == true );
  78. CHECK( spec.matches( *tcD ) == false );
  79. CHECK( parseTestSpec( "a*" ).matches( *tcA ) == true );
  80. }
  81. SECTION( "Wildcard at both ends" ) {
  82. TestSpec spec = parseTestSpec( "*name*" );
  83. CHECK( spec.hasFilters() == true );
  84. CHECK( spec.matches( *tcA ) == false );
  85. CHECK( spec.matches( *tcB ) == false );
  86. CHECK( spec.matches( *tcC ) == true );
  87. CHECK( spec.matches( *tcD ) == true );
  88. CHECK( parseTestSpec( "*a*" ).matches( *tcA ) == true );
  89. }
  90. SECTION( "Redundant wildcard at the start" ) {
  91. TestSpec spec = parseTestSpec( "*a" );
  92. CHECK( spec.hasFilters() == true );
  93. CHECK( spec.matches( *tcA ) == true );
  94. CHECK( spec.matches( *tcB ) == false );
  95. }
  96. SECTION( "Redundant wildcard at the end" ) {
  97. TestSpec spec = parseTestSpec( "a*" );
  98. CHECK( spec.hasFilters() == true );
  99. CHECK( spec.matches( *tcA ) == true );
  100. CHECK( spec.matches( *tcB ) == false );
  101. }
  102. SECTION( "Redundant wildcard at both ends" ) {
  103. TestSpec spec = parseTestSpec( "*a*" );
  104. CHECK( spec.hasFilters() == true );
  105. CHECK( spec.matches( *tcA ) == true );
  106. CHECK( spec.matches( *tcB ) == false );
  107. }
  108. SECTION( "Wildcard at both ends, redundant at start" ) {
  109. TestSpec spec = parseTestSpec( "*longer*" );
  110. CHECK( spec.hasFilters() == true );
  111. CHECK( spec.matches( *tcA ) == false );
  112. CHECK( spec.matches( *tcB ) == false );
  113. CHECK( spec.matches( *tcC ) == true );
  114. CHECK( spec.matches( *tcD ) == true );
  115. }
  116. SECTION( "Just wildcard" ) {
  117. TestSpec spec = parseTestSpec( "*" );
  118. CHECK( spec.hasFilters() == true );
  119. CHECK( spec.matches( *tcA ) == true );
  120. CHECK( spec.matches( *tcB ) == true );
  121. CHECK( spec.matches( *tcC ) == true );
  122. CHECK( spec.matches( *tcD ) == true );
  123. }
  124. SECTION( "Single tag" ) {
  125. TestSpec spec = parseTestSpec( "[one]" );
  126. CHECK( spec.hasFilters() == true );
  127. CHECK( spec.matches( *tcA ) == false );
  128. CHECK( spec.matches( *tcB ) == true );
  129. CHECK( spec.matches( *tcC ) == false );
  130. }
  131. SECTION( "Single tag, two matches" ) {
  132. TestSpec spec = parseTestSpec( "[x]" );
  133. CHECK( spec.hasFilters() == true );
  134. CHECK( spec.matches( *tcA ) == false );
  135. CHECK( spec.matches( *tcB ) == true );
  136. CHECK( spec.matches( *tcC ) == true );
  137. }
  138. SECTION( "Two tags" ) {
  139. TestSpec spec = parseTestSpec( "[two][x]" );
  140. CHECK( spec.hasFilters() == true );
  141. CHECK( spec.matches( *tcA ) == false );
  142. CHECK( spec.matches( *tcB ) == false );
  143. CHECK( spec.matches( *tcC ) == true );
  144. }
  145. SECTION( "Two tags, spare separated" ) {
  146. TestSpec spec = parseTestSpec( "[two] [x]" );
  147. CHECK( spec.hasFilters() == true );
  148. CHECK( spec.matches( *tcA ) == false );
  149. CHECK( spec.matches( *tcB ) == false );
  150. CHECK( spec.matches( *tcC ) == true );
  151. }
  152. SECTION( "Wildcarded name and tag" ) {
  153. TestSpec spec = parseTestSpec( "*name*[x]" );
  154. CHECK( spec.hasFilters() == true );
  155. CHECK( spec.matches( *tcA ) == false );
  156. CHECK( spec.matches( *tcB ) == false );
  157. CHECK( spec.matches( *tcC ) == true );
  158. CHECK( spec.matches( *tcD ) == false );
  159. }
  160. SECTION( "Single tag exclusion" ) {
  161. TestSpec spec = parseTestSpec( "~[one]" );
  162. CHECK( spec.hasFilters() == true );
  163. CHECK( spec.matches( *tcA ) == true );
  164. CHECK( spec.matches( *tcB ) == false );
  165. CHECK( spec.matches( *tcC ) == false );
  166. }
  167. SECTION( "One tag exclusion and one tag inclusion" ) {
  168. TestSpec spec = parseTestSpec( "~[two][x]" );
  169. CHECK( spec.hasFilters() == true );
  170. CHECK( spec.matches( *tcA ) == false );
  171. CHECK( spec.matches( *tcB ) == true );
  172. CHECK( spec.matches( *tcC ) == false );
  173. }
  174. SECTION( "One tag exclusion and one wldcarded name inclusion" ) {
  175. TestSpec spec = parseTestSpec( "~[two]*name*" );
  176. CHECK( spec.hasFilters() == true );
  177. CHECK( spec.matches( *tcA ) == false );
  178. CHECK( spec.matches( *tcB ) == false );
  179. CHECK( spec.matches( *tcC ) == false );
  180. CHECK( spec.matches( *tcD ) == true );
  181. }
  182. SECTION( "One tag exclusion, using exclude:, and one wldcarded name inclusion" ) {
  183. TestSpec spec = parseTestSpec( "exclude:[two]*name*" );
  184. CHECK( spec.hasFilters() == true );
  185. CHECK( spec.matches( *tcA ) == false );
  186. CHECK( spec.matches( *tcB ) == false );
  187. CHECK( spec.matches( *tcC ) == false );
  188. CHECK( spec.matches( *tcD ) == true );
  189. }
  190. SECTION( "name exclusion" ) {
  191. TestSpec spec = parseTestSpec( "~b" );
  192. CHECK( spec.hasFilters() == true );
  193. CHECK( spec.matches( *tcA ) == true );
  194. CHECK( spec.matches( *tcB ) == false );
  195. CHECK( spec.matches( *tcC ) == false );
  196. CHECK( spec.matches( *tcD ) == true );
  197. }
  198. SECTION( "wildcarded name exclusion" ) {
  199. TestSpec spec = parseTestSpec( "~*name*" );
  200. CHECK( spec.hasFilters() == true );
  201. CHECK( spec.matches( *tcA ) == true );
  202. CHECK( spec.matches( *tcB ) == true );
  203. CHECK( spec.matches( *tcC ) == false );
  204. CHECK( spec.matches( *tcD ) == false );
  205. }
  206. SECTION( "wildcarded name exclusion with tag inclusion" ) {
  207. TestSpec spec = parseTestSpec( "~*name*,[three]" );
  208. CHECK( spec.hasFilters() == true );
  209. CHECK( spec.matches( *tcA ) == true );
  210. CHECK( spec.matches( *tcB ) == true );
  211. CHECK( spec.matches( *tcC ) == true );
  212. CHECK( spec.matches( *tcD ) == false );
  213. }
  214. SECTION( "wildcarded name exclusion, using exclude:, with tag inclusion" ) {
  215. TestSpec spec = parseTestSpec( "exclude:*name*,[three]" );
  216. CHECK( spec.hasFilters() == true );
  217. CHECK( spec.matches( *tcA ) == true );
  218. CHECK( spec.matches( *tcB ) == true );
  219. CHECK( spec.matches( *tcC ) == true );
  220. CHECK( spec.matches( *tcD ) == false );
  221. }
  222. SECTION( "two wildcarded names" ) {
  223. TestSpec spec = parseTestSpec( "\"longer*\"\"*spaces\"" );
  224. CHECK( spec.hasFilters() == true );
  225. CHECK( spec.matches( *tcA ) == false );
  226. CHECK( spec.matches( *tcB ) == false );
  227. CHECK( spec.matches( *tcC ) == true );
  228. CHECK( spec.matches( *tcD ) == false );
  229. }
  230. SECTION( "empty tag" ) {
  231. TestSpec spec = parseTestSpec( "[]" );
  232. CHECK( spec.hasFilters() == false );
  233. CHECK( spec.matches( *tcA ) == false );
  234. CHECK( spec.matches( *tcB ) == false );
  235. CHECK( spec.matches( *tcC ) == false );
  236. CHECK( spec.matches( *tcD ) == false );
  237. }
  238. SECTION( "empty quoted name" ) {
  239. TestSpec spec = parseTestSpec( "\"\"" );
  240. CHECK( spec.hasFilters() == false );
  241. CHECK( spec.matches( *tcA ) == false );
  242. CHECK( spec.matches( *tcB ) == false );
  243. CHECK( spec.matches( *tcC ) == false );
  244. CHECK( spec.matches( *tcD ) == false );
  245. }
  246. SECTION( "quoted string followed by tag exclusion" ) {
  247. TestSpec spec = parseTestSpec( "\"*name*\"~[.]" );
  248. CHECK( spec.hasFilters() == true );
  249. CHECK( spec.matches( *tcA ) == false );
  250. CHECK( spec.matches( *tcB ) == false );
  251. CHECK( spec.matches( *tcC ) == false );
  252. CHECK( spec.matches( *tcD ) == true );
  253. }
  254. SECTION( "Leading and trailing spaces in test spec" ) {
  255. TestSpec spec = parseTestSpec( "\" aardvark \"" );
  256. CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
  257. CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
  258. CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
  259. CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
  260. CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
  261. }
  262. SECTION( "Leading and trailing spaces in test name" ) {
  263. TestSpec spec = parseTestSpec( "aardvark" );
  264. CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
  265. CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
  266. CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
  267. CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
  268. CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
  269. }
  270. SECTION("Shortened hide tags are split apart when parsing") {
  271. TestSpec spec = parseTestSpec("[.foo]");
  272. CHECK(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
  273. CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
  274. }
  275. SECTION("Shortened hide tags also properly handle exclusion") {
  276. TestSpec spec = parseTestSpec("~[.foo]");
  277. CHECK_FALSE(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
  278. CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
  279. CHECK_FALSE(spec.matches(*fakeTestCase("only hidden", "[.]")));
  280. CHECK(spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")));
  281. }
  282. }
  283. TEST_CASE("#1905 -- test spec parser properly clears internal state between compound tests", "[command-line][test-spec]") {
  284. using Catch::parseTestSpec;
  285. using Catch::TestSpec;
  286. // We ask for one of 2 different tests and the latter one of them has a , in name that needs escaping
  287. TestSpec spec = parseTestSpec(R"("spec . char","spec \, char")");
  288. REQUIRE(spec.matches(*fakeTestCase("spec . char")));
  289. REQUIRE(spec.matches(*fakeTestCase("spec , char")));
  290. REQUIRE_FALSE(spec.matches(*fakeTestCase(R"(spec \, char)")));
  291. }
  292. TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spec]") {
  293. using Catch::parseTestSpec;
  294. using Catch::TestSpec;
  295. SECTION("Various parentheses") {
  296. TestSpec spec = parseTestSpec(R"(spec {a} char,spec \[a] char)");
  297. REQUIRE(spec.matches(*fakeTestCase(R"(spec {a} char)")));
  298. REQUIRE(spec.matches(*fakeTestCase(R"(spec [a] char)")));
  299. REQUIRE_FALSE(spec.matches(*fakeTestCase("differs but has similar tag", "[a]")));
  300. }
  301. SECTION("backslash in test name") {
  302. TestSpec spec = parseTestSpec(R"(spec \\ char)");
  303. REQUIRE(spec.matches(*fakeTestCase(R"(spec \ char)")));
  304. }
  305. }
  306. TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
  307. using namespace Catch::Matchers;
  308. Catch::ConfigData config;
  309. auto cli = Catch::makeCommandLineParser(config);
  310. SECTION("empty args don't cause a crash") {
  311. auto result = cli.parse({""});
  312. CHECK(result);
  313. CHECK(config.processName == "");
  314. }
  315. SECTION("default - no arguments") {
  316. auto result = cli.parse({"test"});
  317. CHECK(result);
  318. CHECK(config.processName == "test");
  319. CHECK(config.shouldDebugBreak == false);
  320. CHECK(config.abortAfter == -1);
  321. CHECK(config.noThrow == false);
  322. CHECK( config.reporterSpecifications.empty() );
  323. Catch::Config cfg(config);
  324. CHECK_FALSE(cfg.hasTestFilters());
  325. // The Config is responsible for mixing in the default reporter
  326. auto expectedReporter =
  327. #if defined( CATCH_CONFIG_DEFAULT_REPORTER )
  328. CATCH_CONFIG_DEFAULT_REPORTER
  329. #else
  330. "console"
  331. #endif
  332. ;
  333. CHECK( cfg.getReporterSpecs().size() == 1 );
  334. CHECK( cfg.getReporterSpecs()[0] ==
  335. Catch::ReporterSpec{ expectedReporter, {}, {}, {} } );
  336. CHECK( cfg.getProcessedReporterSpecs().size() == 1 );
  337. CHECK( cfg.getProcessedReporterSpecs()[0] ==
  338. Catch::ProcessedReporterSpec{ expectedReporter,
  339. std::string{},
  340. Catch::ColourMode::PlatformDefault,
  341. {} } );
  342. }
  343. SECTION("test lists") {
  344. SECTION("Specify one test case using") {
  345. auto result = cli.parse({"test", "test1"});
  346. CHECK(result);
  347. Catch::Config cfg(config);
  348. REQUIRE(cfg.hasTestFilters());
  349. REQUIRE(cfg.testSpec().matches(*fakeTestCase("notIncluded")) == false);
  350. REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")));
  351. }
  352. SECTION("Specify one test case exclusion using exclude:") {
  353. auto result = cli.parse({"test", "exclude:test1"});
  354. CHECK(result);
  355. Catch::Config cfg(config);
  356. REQUIRE(cfg.hasTestFilters());
  357. REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
  358. REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
  359. }
  360. SECTION("Specify one test case exclusion using ~") {
  361. auto result = cli.parse({"test", "~test1"});
  362. CHECK(result);
  363. Catch::Config cfg(config);
  364. REQUIRE(cfg.hasTestFilters());
  365. REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
  366. REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
  367. }
  368. }
  369. SECTION("reporter") {
  370. using vec_Specs = std::vector<Catch::ReporterSpec>;
  371. using namespace std::string_literals;
  372. SECTION("-r/console") {
  373. auto result = cli.parse({"test", "-r", "console"});
  374. CAPTURE(result.errorMessage());
  375. CHECK(result);
  376. REQUIRE( config.reporterSpecifications ==
  377. vec_Specs{ { "console", {}, {}, {} } } );
  378. }
  379. SECTION("-r/xml") {
  380. auto result = cli.parse({"test", "-r", "xml"});
  381. CAPTURE(result.errorMessage());
  382. CHECK(result);
  383. REQUIRE( config.reporterSpecifications ==
  384. vec_Specs{ { "xml", {}, {}, {} } } );
  385. }
  386. SECTION("--reporter/junit") {
  387. auto result = cli.parse({"test", "--reporter", "junit"});
  388. CAPTURE(result.errorMessage());
  389. CHECK(result);
  390. REQUIRE( config.reporterSpecifications ==
  391. vec_Specs{ { "junit", {}, {}, {} } } );
  392. }
  393. SECTION("must match one of the available ones") {
  394. auto result = cli.parse({"test", "--reporter", "unsupported"});
  395. CHECK(!result);
  396. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Unrecognized reporter"));
  397. }
  398. SECTION("With output file") {
  399. auto result = cli.parse({ "test", "-r", "console::out=out.txt" });
  400. CAPTURE(result.errorMessage());
  401. CHECK(result);
  402. REQUIRE( config.reporterSpecifications ==
  403. vec_Specs{ { "console", "out.txt"s, {}, {} } } );
  404. }
  405. SECTION("With Windows-like absolute path as output file") {
  406. auto result = cli.parse({ "test", "-r", "console::out=C:\\Temp\\out.txt" });
  407. CAPTURE(result.errorMessage());
  408. CHECK(result);
  409. REQUIRE( config.reporterSpecifications ==
  410. vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } );
  411. }
  412. SECTION("Multiple reporters") {
  413. SECTION("All with output files") {
  414. CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }));
  415. REQUIRE( config.reporterSpecifications ==
  416. vec_Specs{ { "xml", "output.xml"s, {}, {} },
  417. { "junit", "output-junit.xml"s, {}, {} } } );
  418. }
  419. SECTION("Mixed output files and default output") {
  420. CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }));
  421. REQUIRE( config.reporterSpecifications ==
  422. vec_Specs{ { "xml", "output.xml"s, {}, {} },
  423. { "console", {}, {}, {} } } );
  424. }
  425. SECTION("cannot have multiple reporters with default output") {
  426. auto result = cli.parse({ "test", "-r", "console", "-r", "xml::out=output.xml", "-r", "junit" });
  427. CHECK(!result);
  428. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Only one reporter may have unspecified output file."));
  429. }
  430. }
  431. }
  432. SECTION("debugger") {
  433. SECTION("-b") {
  434. CHECK(cli.parse({"test", "-b"}));
  435. REQUIRE(config.shouldDebugBreak == true);
  436. }
  437. SECTION("--break") {
  438. CHECK(cli.parse({"test", "--break"}));
  439. REQUIRE(config.shouldDebugBreak);
  440. }
  441. }
  442. SECTION("abort") {
  443. SECTION("-a aborts after first failure") {
  444. CHECK(cli.parse({"test", "-a"}));
  445. REQUIRE(config.abortAfter == 1);
  446. }
  447. SECTION("-x 2 aborts after two failures") {
  448. CHECK(cli.parse({"test", "-x", "2"}));
  449. REQUIRE(config.abortAfter == 2);
  450. }
  451. SECTION("-x must be numeric") {
  452. auto result = cli.parse({"test", "-x", "oops"});
  453. CHECK(!result);
  454. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("convert") && ContainsSubstring("oops"));
  455. }
  456. SECTION("wait-for-keypress") {
  457. SECTION("Accepted options") {
  458. using tuple_type = std::tuple<char const*, Catch::WaitForKeypress::When>;
  459. auto input = GENERATE(table<char const*, Catch::WaitForKeypress::When>({
  460. tuple_type{"never", Catch::WaitForKeypress::Never},
  461. tuple_type{"start", Catch::WaitForKeypress::BeforeStart},
  462. tuple_type{"exit", Catch::WaitForKeypress::BeforeExit},
  463. tuple_type{"both", Catch::WaitForKeypress::BeforeStartAndExit},
  464. }));
  465. CHECK(cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}));
  466. REQUIRE(config.waitForKeypress == std::get<1>(input));
  467. }
  468. SECTION("invalid options are reported") {
  469. auto result = cli.parse({"test", "--wait-for-keypress", "sometimes"});
  470. CHECK(!result);
  471. #ifndef CATCH_CONFIG_DISABLE_MATCHERS
  472. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("never") && ContainsSubstring("both"));
  473. #endif
  474. }
  475. }
  476. }
  477. SECTION("nothrow") {
  478. SECTION("-e") {
  479. CHECK(cli.parse({"test", "-e"}));
  480. REQUIRE(config.noThrow);
  481. }
  482. SECTION("--nothrow") {
  483. CHECK(cli.parse({"test", "--nothrow"}));
  484. REQUIRE(config.noThrow);
  485. }
  486. }
  487. SECTION("output filename") {
  488. SECTION("-o filename") {
  489. CHECK(cli.parse({"test", "-o", "filename.ext"}));
  490. REQUIRE(config.defaultOutputFilename == "filename.ext");
  491. }
  492. SECTION("--out") {
  493. CHECK(cli.parse({"test", "--out", "filename.ext"}));
  494. REQUIRE(config.defaultOutputFilename == "filename.ext");
  495. }
  496. }
  497. SECTION("combinations") {
  498. SECTION("Single character flags can be combined") {
  499. CHECK(cli.parse({"test", "-abe"}));
  500. CHECK(config.abortAfter == 1);
  501. CHECK(config.shouldDebugBreak);
  502. CHECK(config.noThrow == true);
  503. }
  504. }
  505. SECTION( "use-colour") {
  506. using Catch::ColourMode;
  507. SECTION( "without option" ) {
  508. CHECK(cli.parse({"test"}));
  509. REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
  510. }
  511. SECTION( "auto" ) {
  512. CHECK( cli.parse( { "test", "--colour-mode", "default" } ) );
  513. REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
  514. }
  515. SECTION( "yes" ) {
  516. CHECK(cli.parse({"test", "--colour-mode", "ansi"}));
  517. REQUIRE( config.defaultColourMode == ColourMode::ANSI );
  518. }
  519. SECTION( "no" ) {
  520. CHECK(cli.parse({"test", "--colour-mode", "none"}));
  521. REQUIRE( config.defaultColourMode == ColourMode::None );
  522. }
  523. SECTION( "error" ) {
  524. auto result = cli.parse({"test", "--colour-mode", "wrong"});
  525. CHECK( !result );
  526. CHECK_THAT( result.errorMessage(), ContainsSubstring( "colour mode must be one of" ) );
  527. }
  528. }
  529. SECTION("Benchmark options") {
  530. SECTION("samples") {
  531. CHECK(cli.parse({ "test", "--benchmark-samples=200" }));
  532. REQUIRE(config.benchmarkSamples == 200);
  533. }
  534. SECTION("resamples") {
  535. CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));
  536. REQUIRE(config.benchmarkResamples == 20000);
  537. }
  538. SECTION("confidence-interval") {
  539. CHECK(cli.parse({ "test", "--benchmark-confidence-interval=0.99" }));
  540. REQUIRE(config.benchmarkConfidenceInterval == Catch::Approx(0.99));
  541. }
  542. SECTION("no-analysis") {
  543. CHECK(cli.parse({ "test", "--benchmark-no-analysis" }));
  544. REQUIRE(config.benchmarkNoAnalysis);
  545. }
  546. SECTION("warmup-time") {
  547. CHECK(cli.parse({ "test", "--benchmark-warmup-time=10" }));
  548. REQUIRE(config.benchmarkWarmupTime == 10);
  549. }
  550. }
  551. }
  552. TEST_CASE("Parsing sharding-related cli flags", "[sharding]") {
  553. using namespace Catch::Matchers;
  554. Catch::ConfigData config;
  555. auto cli = Catch::makeCommandLineParser(config);
  556. SECTION("shard-count") {
  557. CHECK(cli.parse({ "test", "--shard-count=8" }));
  558. REQUIRE(config.shardCount == 8);
  559. }
  560. SECTION("Negative shard count reports error") {
  561. auto result = cli.parse({ "test", "--shard-count=-1" });
  562. CHECK_FALSE(result);
  563. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Shard count must be a positive number"));
  564. }
  565. SECTION("Zero shard count reports error") {
  566. auto result = cli.parse({ "test", "--shard-count=0" });
  567. CHECK_FALSE(result);
  568. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Shard count must be a positive number"));
  569. }
  570. SECTION("shard-index") {
  571. CHECK(cli.parse({ "test", "--shard-index=2" }));
  572. REQUIRE(config.shardIndex == 2);
  573. }
  574. SECTION("Negative shard index reports error") {
  575. auto result = cli.parse({ "test", "--shard-index=-12" });
  576. CHECK_FALSE(result);
  577. REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Shard index must be a non-negative number"));
  578. }
  579. SECTION("Shard index 0 is accepted") {
  580. CHECK(cli.parse({ "test", "--shard-index=0" }));
  581. REQUIRE(config.shardIndex == 0);
  582. }
  583. }
  584. TEST_CASE( "Parsing warnings", "[cli][warnings]" ) {
  585. using Catch::WarnAbout;
  586. Catch::ConfigData config;
  587. auto cli = Catch::makeCommandLineParser( config );
  588. SECTION( "NoAssertions" ) {
  589. REQUIRE(cli.parse( { "test", "-w", "NoAssertions" } ));
  590. REQUIRE( config.warnings == WarnAbout::NoAssertions );
  591. }
  592. SECTION( "NoTests is no longer supported" ) {
  593. REQUIRE_FALSE(cli.parse( { "test", "-w", "NoTests" } ));
  594. }
  595. SECTION( "Combining multiple warnings" ) {
  596. REQUIRE( cli.parse( { "test",
  597. "--warn", "NoAssertions",
  598. "--warn", "UnmatchedTestSpec" } ) );
  599. REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) );
  600. }
  601. }
  602. TEST_CASE("Test with special, characters \"in name", "[cli][regression]") {
  603. // This test case succeeds if we can invoke it from the CLI
  604. SUCCEED();
  605. }
  606. TEST_CASE("Various suspicious reporter specs are rejected",
  607. "[cli][reporter-spec][approvals]") {
  608. Catch::ConfigData config;
  609. auto cli = Catch::makeCommandLineParser( config );
  610. auto spec = GENERATE( as<std::string>{},
  611. "",
  612. "::console",
  613. "console::",
  614. "console::some-file::",
  615. "::console::some-file::" );
  616. CAPTURE( spec );
  617. auto result = cli.parse( { "test", "--reporter", spec } );
  618. REQUIRE_FALSE( result );
  619. }
  620. TEST_CASE("Win32 colour implementation is compile-time optional",
  621. "[approvals][cli][colours]") {
  622. Catch::ConfigData config;
  623. auto cli = Catch::makeCommandLineParser( config );
  624. auto result = cli.parse( { "test", "--colour-mode", "win32" } );
  625. #if defined( CATCH_CONFIG_COLOUR_WIN32 )
  626. REQUIRE( result );
  627. #else
  628. REQUIRE_FALSE( result );
  629. #endif
  630. }