GeneratorsImpl.tests.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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. #if defined( __GNUC__ ) || defined( __clang__ )
  7. # pragma GCC diagnostic ignored "-Wfloat-equal"
  8. #endif
  9. #include <catch2/catch_approx.hpp>
  10. #include <catch2/catch_test_macros.hpp>
  11. #include <catch2/generators/catch_generator_exception.hpp>
  12. #include <catch2/generators/catch_generators_adapters.hpp>
  13. #include <catch2/generators/catch_generators_random.hpp>
  14. #include <catch2/generators/catch_generators_range.hpp>
  15. // Tests of generator implementation details
  16. TEST_CASE("Generators internals", "[generators][internals]") {
  17. using namespace Catch::Generators;
  18. SECTION("Single value") {
  19. auto gen = value(123);
  20. REQUIRE(gen.get() == 123);
  21. REQUIRE_FALSE(gen.next());
  22. }
  23. SECTION("Preset values") {
  24. auto gen = values({ 1, 3, 5 });
  25. REQUIRE(gen.get() == 1);
  26. REQUIRE(gen.next());
  27. REQUIRE(gen.get() == 3);
  28. REQUIRE(gen.next());
  29. REQUIRE(gen.get() == 5);
  30. REQUIRE_FALSE(gen.next());
  31. }
  32. SECTION("Generator combinator") {
  33. auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
  34. REQUIRE(gen.get() == 1);
  35. REQUIRE(gen.next());
  36. REQUIRE(gen.get() == 5);
  37. REQUIRE(gen.next());
  38. REQUIRE(gen.get() == 2);
  39. REQUIRE(gen.next());
  40. REQUIRE(gen.get() == 4);
  41. REQUIRE(gen.next());
  42. REQUIRE(gen.get() == 0);
  43. REQUIRE_FALSE(gen.next());
  44. }
  45. SECTION("Explicitly typed generator sequence") {
  46. auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
  47. // This just checks that the type is std::string:
  48. REQUIRE(gen.get().size() == 2);
  49. // Iterate over the generator
  50. REQUIRE(gen.get() == "aa");
  51. REQUIRE(gen.next());
  52. REQUIRE(gen.get() == "bb");
  53. REQUIRE(gen.next());
  54. REQUIRE(gen.get() == "cc");
  55. REQUIRE_FALSE(gen.next());
  56. }
  57. SECTION("Filter generator") {
  58. // Normal usage
  59. SECTION("Simple filtering") {
  60. auto gen = filter([](int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
  61. REQUIRE(gen.get() == 1);
  62. REQUIRE(gen.next());
  63. REQUIRE(gen.get() == 3);
  64. REQUIRE_FALSE(gen.next());
  65. }
  66. SECTION("Filter out multiple elements at the start and end") {
  67. auto gen = filter([](int i) { return i != 2; }, values({ 2, 2, 1, 3, 2, 2 }));
  68. REQUIRE(gen.get() == 1);
  69. REQUIRE(gen.next());
  70. REQUIRE(gen.get() == 3);
  71. REQUIRE_FALSE(gen.next());
  72. }
  73. SECTION("Throws on construction if it can't get initial element") {
  74. REQUIRE_THROWS_AS(filter([](int) { return false; }, value(1)), Catch::GeneratorException);
  75. REQUIRE_THROWS_AS(
  76. filter([](int) { return false; }, values({ 1, 2, 3 })),
  77. Catch::GeneratorException);
  78. }
  79. }
  80. SECTION("Take generator") {
  81. SECTION("Take less") {
  82. auto gen = take(2, values({ 1, 2, 3 }));
  83. REQUIRE(gen.get() == 1);
  84. REQUIRE(gen.next());
  85. REQUIRE(gen.get() == 2);
  86. REQUIRE_FALSE(gen.next());
  87. }
  88. SECTION("Take more") {
  89. auto gen = take(2, value(1));
  90. REQUIRE(gen.get() == 1);
  91. REQUIRE_FALSE(gen.next());
  92. }
  93. }
  94. SECTION("Map with explicit return type") {
  95. auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
  96. REQUIRE(gen.get() == 2.0);
  97. REQUIRE(gen.next());
  98. REQUIRE(gen.get() == 4.0);
  99. REQUIRE(gen.next());
  100. REQUIRE(gen.get() == 6.0);
  101. REQUIRE_FALSE(gen.next());
  102. }
  103. SECTION("Map with deduced return type") {
  104. auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
  105. REQUIRE(gen.get() == 2.0);
  106. REQUIRE(gen.next());
  107. REQUIRE(gen.get() == 4.0);
  108. REQUIRE(gen.next());
  109. REQUIRE(gen.get() == 6.0);
  110. REQUIRE_FALSE(gen.next());
  111. }
  112. SECTION("Repeat") {
  113. SECTION("Singular repeat") {
  114. auto gen = repeat(1, value(3));
  115. REQUIRE(gen.get() == 3);
  116. REQUIRE_FALSE(gen.next());
  117. }
  118. SECTION("Actual repeat") {
  119. auto gen = repeat(2, values({ 1, 2, 3 }));
  120. REQUIRE(gen.get() == 1);
  121. REQUIRE(gen.next());
  122. REQUIRE(gen.get() == 2);
  123. REQUIRE(gen.next());
  124. REQUIRE(gen.get() == 3);
  125. REQUIRE(gen.next());
  126. REQUIRE(gen.get() == 1);
  127. REQUIRE(gen.next());
  128. REQUIRE(gen.get() == 2);
  129. REQUIRE(gen.next());
  130. REQUIRE(gen.get() == 3);
  131. REQUIRE_FALSE(gen.next());
  132. }
  133. }
  134. SECTION("Range") {
  135. SECTION("Positive auto step") {
  136. SECTION("Integer") {
  137. auto gen = range(-2, 2);
  138. REQUIRE(gen.get() == -2);
  139. REQUIRE(gen.next());
  140. REQUIRE(gen.get() == -1);
  141. REQUIRE(gen.next());
  142. REQUIRE(gen.get() == 0);
  143. REQUIRE(gen.next());
  144. REQUIRE(gen.get() == 1);
  145. REQUIRE_FALSE(gen.next());
  146. }
  147. }
  148. SECTION("Negative auto step") {
  149. SECTION("Integer") {
  150. auto gen = range(2, -2);
  151. REQUIRE(gen.get() == 2);
  152. REQUIRE(gen.next());
  153. REQUIRE(gen.get() == 1);
  154. REQUIRE(gen.next());
  155. REQUIRE(gen.get() == 0);
  156. REQUIRE(gen.next());
  157. REQUIRE(gen.get() == -1);
  158. REQUIRE_FALSE(gen.next());
  159. }
  160. }
  161. SECTION("Positive manual step") {
  162. SECTION("Integer") {
  163. SECTION("Exact") {
  164. auto gen = range(-7, 5, 3);
  165. REQUIRE(gen.get() == -7);
  166. REQUIRE(gen.next());
  167. REQUIRE(gen.get() == -4);
  168. REQUIRE(gen.next());
  169. REQUIRE(gen.get() == -1);
  170. REQUIRE(gen.next());
  171. REQUIRE(gen.get() == 2);
  172. REQUIRE_FALSE(gen.next());
  173. }
  174. SECTION("Slightly over end") {
  175. auto gen = range(-7, 4, 3);
  176. REQUIRE(gen.get() == -7);
  177. REQUIRE(gen.next());
  178. REQUIRE(gen.get() == -4);
  179. REQUIRE(gen.next());
  180. REQUIRE(gen.get() == -1);
  181. REQUIRE(gen.next());
  182. REQUIRE(gen.get() == 2);
  183. REQUIRE_FALSE(gen.next());
  184. }
  185. SECTION("Slightly under end") {
  186. auto gen = range(-7, 6, 3);
  187. REQUIRE(gen.get() == -7);
  188. REQUIRE(gen.next());
  189. REQUIRE(gen.get() == -4);
  190. REQUIRE(gen.next());
  191. REQUIRE(gen.get() == -1);
  192. REQUIRE(gen.next());
  193. REQUIRE(gen.get() == 2);
  194. REQUIRE(gen.next());
  195. REQUIRE(gen.get() == 5);
  196. REQUIRE_FALSE(gen.next());
  197. }
  198. }
  199. SECTION("Floating Point") {
  200. using Catch::Approx;
  201. SECTION("Exact") {
  202. const auto rangeStart = -1.;
  203. const auto rangeEnd = 1.;
  204. const auto step = .1;
  205. auto gen = range(rangeStart, rangeEnd, step);
  206. auto expected = rangeStart;
  207. while( (rangeEnd - expected) > step ) {
  208. INFO( "Current expected value is " << expected );
  209. REQUIRE(gen.get() == Approx(expected));
  210. REQUIRE(gen.next());
  211. expected += step;
  212. }
  213. REQUIRE(gen.get() == Approx( rangeEnd ) );
  214. REQUIRE_FALSE(gen.next());
  215. }
  216. SECTION("Slightly over end") {
  217. const auto rangeStart = -1.;
  218. const auto rangeEnd = 1.;
  219. const auto step = .3;
  220. auto gen = range(rangeStart, rangeEnd, step);
  221. auto expected = rangeStart;
  222. while( (rangeEnd - expected) > step ) {
  223. INFO( "Current expected value is " << expected );
  224. REQUIRE(gen.get() == Approx(expected));
  225. REQUIRE(gen.next());
  226. expected += step;
  227. }
  228. REQUIRE_FALSE(gen.next());
  229. }
  230. SECTION("Slightly under end") {
  231. const auto rangeStart = -1.;
  232. const auto rangeEnd = .9;
  233. const auto step = .3;
  234. auto gen = range(rangeStart, rangeEnd, step);
  235. auto expected = rangeStart;
  236. while( (rangeEnd - expected) > step ) {
  237. INFO( "Current expected value is " << expected );
  238. REQUIRE(gen.get() == Approx(expected));
  239. REQUIRE(gen.next());
  240. expected += step;
  241. }
  242. REQUIRE_FALSE(gen.next());
  243. }
  244. }
  245. }
  246. SECTION("Negative manual step") {
  247. SECTION("Integer") {
  248. SECTION("Exact") {
  249. auto gen = range(5, -7, -3);
  250. REQUIRE(gen.get() == 5);
  251. REQUIRE(gen.next());
  252. REQUIRE(gen.get() == 2);
  253. REQUIRE(gen.next());
  254. REQUIRE(gen.get() == -1);
  255. REQUIRE(gen.next());
  256. REQUIRE(gen.get() == -4);
  257. REQUIRE_FALSE(gen.next());
  258. }
  259. SECTION("Slightly over end") {
  260. auto gen = range(5, -6, -3);
  261. REQUIRE(gen.get() == 5);
  262. REQUIRE(gen.next());
  263. REQUIRE(gen.get() == 2);
  264. REQUIRE(gen.next());
  265. REQUIRE(gen.get() == -1);
  266. REQUIRE(gen.next());
  267. REQUIRE(gen.get() == -4);
  268. REQUIRE_FALSE(gen.next());
  269. }
  270. SECTION("Slightly under end") {
  271. auto gen = range(5, -8, -3);
  272. REQUIRE(gen.get() == 5);
  273. REQUIRE(gen.next());
  274. REQUIRE(gen.get() == 2);
  275. REQUIRE(gen.next());
  276. REQUIRE(gen.get() == -1);
  277. REQUIRE(gen.next());
  278. REQUIRE(gen.get() == -4);
  279. REQUIRE(gen.next());
  280. REQUIRE(gen.get() == -7);
  281. REQUIRE_FALSE(gen.next());
  282. }
  283. }
  284. }
  285. }
  286. }
  287. // todo: uncopyable type used in a generator
  288. // idea: uncopyable tag type for a stupid generator
  289. namespace {
  290. struct non_copyable {
  291. non_copyable() = default;
  292. non_copyable(non_copyable const&) = delete;
  293. non_copyable& operator=(non_copyable const&) = delete;
  294. int value = -1;
  295. };
  296. // This class shows how to implement a simple generator for Catch tests
  297. class TestGen : public Catch::Generators::IGenerator<int> {
  298. int current_number;
  299. public:
  300. TestGen(non_copyable const& nc):
  301. current_number(nc.value) {}
  302. int const& get() const override;
  303. bool next() override {
  304. return false;
  305. }
  306. };
  307. // Avoids -Wweak-vtables
  308. int const& TestGen::get() const {
  309. return current_number;
  310. }
  311. }
  312. TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
  313. auto value = GENERATE(take(10, random(0, 10)));
  314. non_copyable nc; nc.value = value;
  315. // neither `GENERATE_COPY` nor plain `GENERATE` would compile here
  316. auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(Catch::Detail::make_unique<TestGen>(nc)));
  317. REQUIRE(value == value2);
  318. }
  319. TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
  320. // Verify Issue #1809 fix, only needs to compile.
  321. auto a = GENERATE_COPY(1, 2);
  322. (void)a;
  323. auto b = GENERATE_COPY(as<long>{}, 1, 2);
  324. (void)b;
  325. int i = 1;
  326. int j = 2;
  327. auto c = GENERATE_COPY(i, j);
  328. (void)c;
  329. auto d = GENERATE_COPY(as<long>{}, i, j);
  330. (void)d;
  331. SUCCEED();
  332. }
  333. TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
  334. SECTION("Integer") {
  335. auto random1 = Catch::Generators::random(0, 1000);
  336. auto random2 = Catch::Generators::random(0, 1000);
  337. size_t same = 0;
  338. for (size_t i = 0; i < 1000; ++i) {
  339. same += random1.get() == random2.get();
  340. random1.next(); random2.next();
  341. }
  342. // Because the previous low bound failed CI couple of times,
  343. // we use a very high threshold of 20% before failure is reported.
  344. REQUIRE(same < 200);
  345. }
  346. SECTION("Float") {
  347. auto random1 = Catch::Generators::random(0., 1000.);
  348. auto random2 = Catch::Generators::random(0., 1000.);
  349. size_t same = 0;
  350. for (size_t i = 0; i < 1000; ++i) {
  351. same += random1.get() == random2.get();
  352. random1.next(); random2.next();
  353. }
  354. // Because the previous low bound failed CI couple of times,
  355. // we use a very high threshold of 20% before failure is reported.
  356. REQUIRE(same < 200);
  357. }
  358. }
  359. TEST_CASE("#2040 - infinite compilation recursion in GENERATE with MSVC", "[generators][compilation][approvals]") {
  360. int x = 42;
  361. auto test = GENERATE_COPY(1, x, 2 * x);
  362. CHECK(test < 100);
  363. }
  364. namespace {
  365. static bool always_true(int) {
  366. return true;
  367. }
  368. static bool is_even(int n) {
  369. return n % 2 == 0;
  370. }
  371. static bool is_multiple_of_3(int n) {
  372. return n % 3 == 0;
  373. }
  374. }
  375. TEST_CASE("GENERATE handles function (pointers)", "[generators][compilation][approvals]") {
  376. auto f = GENERATE(always_true, is_even, is_multiple_of_3);
  377. REQUIRE(f(6));
  378. }
  379. TEST_CASE("GENERATE decays arrays", "[generators][compilation][approvals]") {
  380. auto str = GENERATE("abc", "def", "gh");
  381. STATIC_REQUIRE(std::is_same<decltype(str), const char*>::value);
  382. }
  383. TEST_CASE("Generators count returned elements", "[generators][approvals]") {
  384. auto generator = Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
  385. REQUIRE( generator.currentElementIndex() == 0 );
  386. REQUIRE( generator.countedNext() );
  387. REQUIRE( generator.currentElementIndex() == 1 );
  388. REQUIRE( generator.countedNext() );
  389. REQUIRE( generator.currentElementIndex() == 2 );
  390. REQUIRE_FALSE( generator.countedNext() );
  391. REQUIRE( generator.currentElementIndex() == 2 );
  392. }
  393. TEST_CASE( "Generators can stringify their elements",
  394. "[generators][approvals]" ) {
  395. auto generator =
  396. Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
  397. REQUIRE( generator.currentElementAsString() == "1"_catch_sr );
  398. REQUIRE( generator.countedNext() );
  399. REQUIRE( generator.currentElementAsString() == "2"_catch_sr );
  400. REQUIRE( generator.countedNext() );
  401. REQUIRE( generator.currentElementAsString() == "3"_catch_sr );
  402. }
  403. namespace {
  404. class CustomStringifyGenerator
  405. : public Catch::Generators::IGenerator<bool> {
  406. bool m_first = true;
  407. std::string stringifyImpl() const override {
  408. return m_first ? "first" : "second";
  409. }
  410. bool next() override {
  411. if ( m_first ) {
  412. m_first = false;
  413. return true;
  414. }
  415. return false;
  416. }
  417. public:
  418. bool const& get() const override;
  419. };
  420. // Avoids -Wweak-vtables
  421. bool const& CustomStringifyGenerator::get() const { return m_first; }
  422. } // namespace
  423. TEST_CASE( "Generators can override element stringification",
  424. "[generators][approvals]" ) {
  425. CustomStringifyGenerator generator;
  426. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  427. REQUIRE( generator.countedNext() );
  428. REQUIRE( generator.currentElementAsString() == "second"_catch_sr );
  429. }
  430. namespace {
  431. class StringifyCountingGenerator
  432. : public Catch::Generators::IGenerator<bool> {
  433. bool m_first = true;
  434. mutable size_t m_stringificationCalls = 0;
  435. std::string stringifyImpl() const override {
  436. ++m_stringificationCalls;
  437. return m_first ? "first" : "second";
  438. }
  439. bool next() override {
  440. if ( m_first ) {
  441. m_first = false;
  442. return true;
  443. }
  444. return false;
  445. }
  446. public:
  447. bool const& get() const override;
  448. size_t stringificationCalls() const { return m_stringificationCalls; }
  449. };
  450. // Avoids -Wweak-vtables
  451. bool const& StringifyCountingGenerator::get() const { return m_first; }
  452. } // namespace
  453. TEST_CASE( "Generator element stringification is cached",
  454. "[generators][approvals]" ) {
  455. StringifyCountingGenerator generator;
  456. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  457. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  458. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  459. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  460. REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
  461. REQUIRE( generator.stringificationCalls() == 1 );
  462. }
  463. TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) {
  464. SECTION( "Integer generator" ) {
  465. using Catch::Generators::RandomIntegerGenerator;
  466. RandomIntegerGenerator<int> rng1( 0, 100, 0x1234 ),
  467. rng2( 0, 100, 0x1234 );
  468. for ( size_t i = 0; i < 10; ++i ) {
  469. REQUIRE( rng1.get() == rng2.get() );
  470. rng1.next(); rng2.next();
  471. }
  472. }
  473. SECTION("Float generator") {
  474. using Catch::Generators::RandomFloatingGenerator;
  475. RandomFloatingGenerator<double> rng1( 0., 100., 0x1234 ),
  476. rng2( 0., 100., 0x1234 );
  477. for ( size_t i = 0; i < 10; ++i ) {
  478. REQUIRE( rng1.get() == rng2.get() );
  479. rng1.next();
  480. rng2.next();
  481. }
  482. }
  483. }