1 #include <catch2/catch.hpp>
2 #include <rapidcheck/catch.h>
3 
4 #include "rapidcheck/shrinkable/Operations.h"
5 #include "rapidcheck/shrinkable/Create.h"
6 
7 #include "util/Generators.h"
8 
9 using namespace rc;
10 
11 TEST_CASE("shrinkable::all") {
12   prop("returns true if predicate returns true for all",
__anon0fd8dcd30102null13        [] {
14          // TODO sized ranged
15          int x = *gen::inRange<int>(1, 5);
16          const auto shrinkable = shrinkable::shrinkRecur(
17              x, [](int y) { return seq::range(y - 1, 0); });
18 
19          RC_ASSERT(shrinkable::all(
20              shrinkable,
21              [](const Shrinkable<int> &s) { return s.value() != 0; }));
22        });
23 
24   prop("returns true if predicate returns false for at least one shrinkable",
__anon0fd8dcd30402null25        [] {
26          // TODO sized ranged
27          int x = *gen::inRange<int>(0, 5);
28          const auto shrinkable = shrinkable::just(
29              x, seq::map(seq::range(x - 1, -1), &shrinkable::just<int>));
30 
31          RC_ASSERT(!shrinkable::all(shrinkable,
32                                     [](const Shrinkable<int> &s) {
33                                       return s.value() != 0;
34                                     }));
35        });
36 }
37 
38 TEST_CASE("shrinkable::findLocalMin") {
39   prop("returns the original value if no value matched predicate",
__anon0fd8dcd30602(int x) 40        [](int x) {
41          auto result =
42              shrinkable::findLocalMin(shrinkable::just(x), fn::constant(true));
43          RC_ASSERT(result.first == x);
44        });
45 
46   prop("return zero shrinks if no value matched predicate",
__anon0fd8dcd30702null47        [] {
48          auto result =
49              shrinkable::findLocalMin(shrinkable::just(0), fn::constant(true));
50          RC_ASSERT(result.second == 0U);
51        });
52 
53   prop(
54       "searches by descending into the first value of each shrinks Seq that"
55       " matches the predicate",
__anon0fd8dcd30802null56       [] {
57         const auto expected =
58             *gen::container<std::vector<int>>(gen::inRange<int>(1, 101));
59 
60         const auto pred = [&](const std::vector<int> &x) {
61           int back = x.back();
62           // We want to test that the first value is picked so we accept
63           // both zero and the corresponding value in the expected vector
64           // but since zero comes last, that will never be picked
65           return (x.size() <= expected.size()) &&
66               ((back == 0) || (back == expected[x.size() - 1]));
67         };
68 
69         const auto shrinkable =
70             shrinkable::shrinkRecur(std::vector<int>(),
71                                     [](const std::vector<int> &vec) {
72                                       return seq::map(seq::range<int>(100, -1),
73                                                       [=](int x) {
74                                                         auto shrink = vec;
75                                                         shrink.push_back(x);
76                                                         return shrink;
77                                                       });
78                                     });
79 
80         const auto result = shrinkable::findLocalMin(shrinkable, pred);
81         RC_ASSERT(result.first == expected);
82         RC_ASSERT(result.second == expected.size());
83       });
84 }
85 
86 TEST_CASE("shrinkable::immediateShrinks") {
87   prop(
88       "returns a Seq of the values of the immediate shrinks of the"
89       " Shrinkable",
__anon0fd8dcd30c02(int x, const Seq<int> &seq) 90       [](int x, const Seq<int> &seq) {
91         const auto shrinkable =
92             shrinkable::just(x, seq::map(seq, &shrinkable::just<int>));
93         RC_ASSERT(shrinkable::immediateShrinks(shrinkable) == seq);
94       });
95 }
96 
97 TEST_CASE("shrinkable::walkPath") {
98   prop("returns the shrinkable at the end of the path",
__anon0fd8dcd30d02null99        [] {
100          const auto path = *gen::container<std::vector<std::size_t>>(
101                                gen::inRange<std::size_t>(0, 100));
102          const auto shrinkable =
103              shrinkable::shrinkRecur(std::vector<std::size_t>(),
104                                      [](const std::vector<std::size_t> &lambdaPath) {
105                                        return seq::map(seq::index(),
106                                                        [=](std::size_t i) {
107                                                          auto p = lambdaPath;
108                                                          p.push_back(i);
109                                                          return p;
110                                                        });
111                                      });
112 
113          const auto result = shrinkable::walkPath(shrinkable, path);
114          RC_ASSERT(result);
115          RC_ASSERT(result->value() == path);
116        });
117 
118   prop("returns something if path never goes outside tree",
__anon0fd8dcd31002null119        [] {
120          const auto limit = *gen::inRange<std::size_t>(0, 100);
121          const auto shrinkable = shrinkable::shrinkRecur(
122              std::size_t(0),
123              [=](std::size_t x) { return seq::range<std::size_t>(0, limit); });
124          auto path = *gen::container<std::vector<std::size_t>>(
125              gen::inRange<std::size_t>(0, limit));
126 
127          const auto result = shrinkable::walkPath(shrinkable, path);
128          RC_ASSERT(result);
129        });
130 
131   prop("returns Nothing if path ever goes outside tree",
__anon0fd8dcd31202null132        [] {
133          const auto limit = *gen::inRange<std::size_t>(0, 100);
134          const auto shrinkable = shrinkable::shrinkRecur(
135              std::size_t(0),
136              [=](std::size_t x) { return seq::range<std::size_t>(0, limit); });
137          auto path = *gen::container<std::vector<std::size_t>>(
138              gen::inRange<std::size_t>(0, limit));
139          const auto i = *gen::inRange<std::size_t>(0, path.size() + 1);
140          path.insert(begin(path) + i, limit);
141          const auto result = shrinkable::walkPath(shrinkable, path);
142          RC_ASSERT(!result);
143        });
144 }
145