1 #include "catch.hpp"
2 
3 // Tests of generator implementation details
4 TEST_CASE("Generators internals", "[generators][internals]") {
5     using namespace Catch::Generators;
6 
7     SECTION("Single value") {
8         auto gen = value(123);
9         REQUIRE(gen.get() == 123);
10         REQUIRE_FALSE(gen.next());
11     }
12     SECTION("Preset values") {
13         auto gen = values({ 1, 3, 5 });
14         REQUIRE(gen.get() == 1);
15         REQUIRE(gen.next());
16         REQUIRE(gen.get() == 3);
17         REQUIRE(gen.next());
18         REQUIRE(gen.get() == 5);
19         REQUIRE_FALSE(gen.next());
20     }
21     SECTION("Generator combinator") {
22         auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
23         REQUIRE(gen.get() == 1);
24         REQUIRE(gen.next());
25         REQUIRE(gen.get() == 5);
26         REQUIRE(gen.next());
27         REQUIRE(gen.get() == 2);
28         REQUIRE(gen.next());
29         REQUIRE(gen.get() == 4);
30         REQUIRE(gen.next());
31         REQUIRE(gen.get() == 0);
32         REQUIRE_FALSE(gen.next());
33     }
34     SECTION("Explicitly typed generator sequence") {
35         auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
36         // This just checks that the type is std::string:
37         REQUIRE(gen.get().size() == 2);
38         // Iterate over the generator
39         REQUIRE(gen.get() == "aa");
40         REQUIRE(gen.next());
41         REQUIRE(gen.get() == "bb");
42         REQUIRE(gen.next());
43         REQUIRE(gen.get() == "cc");
44         REQUIRE_FALSE(gen.next());
45     }
46     SECTION("Filter generator") {
47         // Normal usage
__anon85e890760102(int i) 48         auto gen = filter([] (int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
49         REQUIRE(gen.get() == 1);
50         REQUIRE(gen.next());
51         REQUIRE(gen.get() == 3);
52         REQUIRE_FALSE(gen.next());
53 
54         // Completely filtered-out generator should throw on construction
__anon85e890760202(int) 55         REQUIRE_THROWS_AS(filter([] (int) { return false; }, value(1)), Catch::GeneratorException);
56     }
57     SECTION("Take generator") {
58         SECTION("Take less") {
59             auto gen = take(2, values({ 1, 2, 3 }));
60             REQUIRE(gen.get() == 1);
61             REQUIRE(gen.next());
62             REQUIRE(gen.get() == 2);
63             REQUIRE_FALSE(gen.next());
64         }
65         SECTION("Take more") {
66             auto gen = take(2, value(1));
67             REQUIRE(gen.get() == 1);
68             REQUIRE_FALSE(gen.next());
69         }
70     }
71     SECTION("Map with explicit return type") {
__anon85e890760302(int i) 72         auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
73         REQUIRE(gen.get() == 2.0);
74         REQUIRE(gen.next());
75         REQUIRE(gen.get() == 4.0);
76         REQUIRE(gen.next());
77         REQUIRE(gen.get() == 6.0);
78         REQUIRE_FALSE(gen.next());
79     }
80     SECTION("Map with deduced return type") {
__anon85e890760402(int i) 81         auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
82         REQUIRE(gen.get() == 2.0);
83         REQUIRE(gen.next());
84         REQUIRE(gen.get() == 4.0);
85         REQUIRE(gen.next());
86         REQUIRE(gen.get() == 6.0);
87         REQUIRE_FALSE(gen.next());
88     }
89     SECTION("Repeat") {
90         SECTION("Singular repeat") {
91             auto gen = repeat(1, value(3));
92             REQUIRE(gen.get() == 3);
93             REQUIRE_FALSE(gen.next());
94         }
95         SECTION("Actual repeat") {
96             auto gen = repeat(2, values({ 1, 2, 3 }));
97             REQUIRE(gen.get() == 1);
98             REQUIRE(gen.next());
99             REQUIRE(gen.get() == 2);
100             REQUIRE(gen.next());
101             REQUIRE(gen.get() == 3);
102             REQUIRE(gen.next());
103             REQUIRE(gen.get() == 1);
104             REQUIRE(gen.next());
105             REQUIRE(gen.get() == 2);
106             REQUIRE(gen.next());
107             REQUIRE(gen.get() == 3);
108             REQUIRE_FALSE(gen.next());
109         }
110     }
111     SECTION("Range") {
112         SECTION("Positive auto step") {
113             SECTION("Integer") {
114                 auto gen = range(-2, 2);
115                 REQUIRE(gen.get() == -2);
116                 REQUIRE(gen.next());
117                 REQUIRE(gen.get() == -1);
118                 REQUIRE(gen.next());
119                 REQUIRE(gen.get() == 0);
120                 REQUIRE(gen.next());
121                 REQUIRE(gen.get() == 1);
122                 REQUIRE_FALSE(gen.next());
123             }
124         }
125         SECTION("Negative auto step") {
126             SECTION("Integer") {
127                 auto gen = range(2, -2);
128                 REQUIRE(gen.get() == 2);
129                 REQUIRE(gen.next());
130                 REQUIRE(gen.get() == 1);
131                 REQUIRE(gen.next());
132                 REQUIRE(gen.get() == 0);
133                 REQUIRE(gen.next());
134                 REQUIRE(gen.get() == -1);
135                 REQUIRE_FALSE(gen.next());
136             }
137         }
138         SECTION("Positive manual step") {
139             SECTION("Integer") {
140                 SECTION("Exact") {
141                     auto gen = range(-7, 5, 3);
142                     REQUIRE(gen.get() == -7);
143                     REQUIRE(gen.next());
144                     REQUIRE(gen.get() == -4);
145                     REQUIRE(gen.next());
146                     REQUIRE(gen.get() == -1);
147                     REQUIRE(gen.next());
148                     REQUIRE(gen.get() == 2);
149                     REQUIRE_FALSE(gen.next());
150                 }
151                 SECTION("Slightly over end") {
152                     auto gen = range(-7, 4, 3);
153                     REQUIRE(gen.get() == -7);
154                     REQUIRE(gen.next());
155                     REQUIRE(gen.get() == -4);
156                     REQUIRE(gen.next());
157                     REQUIRE(gen.get() == -1);
158                     REQUIRE(gen.next());
159                     REQUIRE(gen.get() == 2);
160                     REQUIRE_FALSE(gen.next());
161                 }
162                 SECTION("Slightly under end") {
163                     auto gen = range(-7, 6, 3);
164                     REQUIRE(gen.get() == -7);
165                     REQUIRE(gen.next());
166                     REQUIRE(gen.get() == -4);
167                     REQUIRE(gen.next());
168                     REQUIRE(gen.get() == -1);
169                     REQUIRE(gen.next());
170                     REQUIRE(gen.get() == 2);
171                     REQUIRE(gen.next());
172                     REQUIRE(gen.get() == 5);
173                     REQUIRE_FALSE(gen.next());
174                 }
175             }
176 
177             SECTION("Floating Point") {
178                 SECTION("Exact") {
179                     const auto rangeStart = -1.;
180                     const auto rangeEnd = 1.;
181                     const auto step = .1;
182 
183                     auto gen = range(rangeStart, rangeEnd, step);
184                     auto expected = rangeStart;
185                     while( (rangeEnd - expected) > step ) {
186                         INFO( "Current expected value is " << expected )
187                         REQUIRE(gen.get() == Approx(expected));
188                         REQUIRE(gen.next());
189 
190                         expected += step;
191                     }
192                     REQUIRE(gen.get() == Approx( rangeEnd ) );
193                     REQUIRE_FALSE(gen.next());
194                 }
195                 SECTION("Slightly over end") {
196                     const auto rangeStart = -1.;
197                     const auto rangeEnd = 1.;
198                     const auto step = .3;
199 
200                     auto gen = range(rangeStart, rangeEnd, step);
201                     auto expected = rangeStart;
202                     while( (rangeEnd - expected) > step ) {
203                        INFO( "Current expected value is " << expected )
204                        REQUIRE(gen.get() == Approx(expected));
205                        REQUIRE(gen.next());
206 
207                        expected += step;
208                     }
209                     REQUIRE_FALSE(gen.next());
210                 }
211                 SECTION("Slightly under end") {
212                     const auto rangeStart = -1.;
213                     const auto rangeEnd = .9;
214                     const auto step = .3;
215 
216                     auto gen = range(rangeStart, rangeEnd, step);
217                     auto expected = rangeStart;
218                     while( (rangeEnd - expected) > step ) {
219                        INFO( "Current expected value is " << expected )
220                        REQUIRE(gen.get() == Approx(expected));
221                        REQUIRE(gen.next());
222 
223                        expected += step;
224                     }
225                     REQUIRE_FALSE(gen.next());
226                 }
227             }
228         }
229         SECTION("Negative manual step") {
230             SECTION("Integer") {
231                 SECTION("Exact") {
232                     auto gen = range(5, -7, -3);
233                     REQUIRE(gen.get() == 5);
234                     REQUIRE(gen.next());
235                     REQUIRE(gen.get() == 2);
236                     REQUIRE(gen.next());
237                     REQUIRE(gen.get() == -1);
238                     REQUIRE(gen.next());
239                     REQUIRE(gen.get() == -4);
240                     REQUIRE_FALSE(gen.next());
241                 }
242                 SECTION("Slightly over end") {
243                     auto gen = range(5, -6, -3);
244                     REQUIRE(gen.get() == 5);
245                     REQUIRE(gen.next());
246                     REQUIRE(gen.get() == 2);
247                     REQUIRE(gen.next());
248                     REQUIRE(gen.get() == -1);
249                     REQUIRE(gen.next());
250                     REQUIRE(gen.get() == -4);
251                     REQUIRE_FALSE(gen.next());
252                 }
253                 SECTION("Slightly under end") {
254                     auto gen = range(5, -8, -3);
255                     REQUIRE(gen.get() == 5);
256                     REQUIRE(gen.next());
257                     REQUIRE(gen.get() == 2);
258                     REQUIRE(gen.next());
259                     REQUIRE(gen.get() == -1);
260                     REQUIRE(gen.next());
261                     REQUIRE(gen.get() == -4);
262                     REQUIRE(gen.next());
263                     REQUIRE(gen.get() == -7);
264                     REQUIRE_FALSE(gen.next());
265                 }
266             }
267         }
268     }
269 
270 }
271 
272 
273 // todo: uncopyable type used in a generator
274 //  idea: uncopyable tag type for a stupid generator
275 
276 namespace {
277 struct non_copyable {
278     non_copyable() = default;
279     non_copyable(non_copyable const&) = delete;
280     non_copyable& operator=(non_copyable const&) = delete;
281     int value = -1;
282 };
283 
284 // This class shows how to implement a simple generator for Catch tests
285 class TestGen : public Catch::Generators::IGenerator<int> {
286     int current_number;
287 public:
288 
TestGen(non_copyable const & nc)289     TestGen(non_copyable const& nc):
290         current_number(nc.value) {}
291 
292     int const& get() const override;
next()293     bool next() override {
294         return false;
295     }
296 };
297 
298 // Avoids -Wweak-vtables
get() const299 int const& TestGen::get() const {
300     return current_number;
301 }
302 
303 }
304 
305 TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
306     auto value = GENERATE(take(10, random(0, 10)));
307 
308     non_copyable nc; nc.value = value;
309     // neither `GENERATE_COPY` nor plain `GENERATE` would compile here
310     auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
311     REQUIRE(value == value2);
312 }
313 
314 TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
315     // Verify Issue #1809 fix, only needs to compile.
316     auto a = GENERATE_COPY(1, 2);
317     (void)a;
318     auto b = GENERATE_COPY(as<long>{}, 1, 2);
319     (void)b;
320     int i = 1;
321     int j = 2;
322     auto c = GENERATE_COPY(i, j);
323     (void)c;
324     auto d = GENERATE_COPY(as<long>{}, i, j);
325     (void)d;
326     SUCCEED();
327 }
328 
329 TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
330     SECTION("Integer") {
331         auto random1 = Catch::Generators::random(0, 1000);
332         auto random2 = Catch::Generators::random(0, 1000);
333         size_t same = 0;
334         for (size_t i = 0; i < 1000; ++i) {
335             same += random1.get() == random2.get();
336             random1.next(); random2.next();
337         }
338         // 0.5% seems like a sane bound for random identical elements within 1000 runs
339         REQUIRE(same < 5);
340     }
341     SECTION("Float") {
342         auto random1 = Catch::Generators::random(0., 1000.);
343         auto random2 = Catch::Generators::random(0., 1000.);
344         size_t same = 0;
345         for (size_t i = 0; i < 1000; ++i) {
346             same += random1.get() == random2.get();
347             random1.next(); random2.next();
348         }
349         // 0.5% seems like a sane bound for random identical elements within 1000 runs
350         REQUIRE(same < 5);
351     }
352 }
353