1 #include <catch2/catch.hpp>
2 #include <rapidcheck/catch.h>
3 
4 #include <algorithm>
5 
6 #include "util/Generators.h"
7 
8 using namespace rc;
9 using namespace rc::detail;
10 
11 namespace {
12 
stringContains(const std::string & str,const std::string & substr)13 bool stringContains(const std::string &str, const std::string &substr) {
14   return str.find(substr) != std::string::npos;
15 }
16 
descriptionContains(const CaseResult & result,const std::string & substr)17 bool descriptionContains(const CaseResult &result, const std::string &substr) {
18   return stringContains(result.description, substr);
19 }
20 
21 } // namespace
22 
23 TEST_CASE("makeMessage") {
24   SECTION("message contains assertion") {
25     REQUIRE(stringContains(makeMessage("", 0, "ASSERT_IT(foo)", ""),
26                            "ASSERT_IT(foo)"));
27   }
28 
29   SECTION("message contains extra") {
30     REQUIRE(
31         stringContains(makeMessage("", 0, "", "foo bar baz"), "foo bar baz"));
32   }
33 
34   SECTION("message is only two lines if extra is empty") {
35     const auto msg = makeMessage("foo.cpp", 0, "foo", "");
36     REQUIRE(std::count(begin(msg), end(msg), '\n') == 1);
37   }
38 
39   SECTION("message contains file and line") {
40     REQUIRE(
41         stringContains(makeMessage("foo.cpp", 1337, "", ""), "foo.cpp:1337"));
42   }
43 }
44 
45 TEST_CASE("makeExpressionMessage") {
46   SECTION("message contains assertion") {
47     REQUIRE(stringContains(makeExpressionMessage("", 0, "ASSERT_IT(foo)", ""),
48                            "ASSERT_IT(foo)"));
49   }
50 
51   SECTION("message contains expansion") {
52     REQUIRE(
53         stringContains(makeExpressionMessage("", 0, "", "a == b"), "a == b"));
54   }
55 
56   SECTION("message contains file and line") {
57     REQUIRE(stringContains(makeExpressionMessage("foo.cpp", 1337, "", ""),
58                            "foo.cpp:1337"));
59   }
60 }
61 
62 TEST_CASE("makeUnthrownExceptionMessage") {
63   SECTION("message contains assertion") {
64     REQUIRE(
65         stringContains(makeUnthrownExceptionMessage("", 0, "ASSERT_IT(foo)"),
66                        "ASSERT_IT(foo)"));
67   }
68 
69   SECTION("message contains file and line") {
70     REQUIRE(stringContains(makeUnthrownExceptionMessage("foo.cpp", 1337, ""),
71                            "foo.cpp:1337"));
72   }
73 }
74 
75 TEST_CASE("makeWrongExceptionMessage") {
76   SECTION("message contains assertion") {
77     REQUIRE(
78         stringContains(makeWrongExceptionMessage("", 0, "ASSERT_IT(foo)", ""),
79                        "ASSERT_IT(foo)"));
80   }
81 
82   SECTION("message contains expected exception") {
83     REQUIRE(
84         stringContains(makeWrongExceptionMessage("", 0, "", "std::exception"),
85                        "std::exception"));
86   }
87 
88   SECTION("message contains file and line") {
89     REQUIRE(stringContains(makeWrongExceptionMessage("foo.cpp", 1337, "", ""),
90                            "foo.cpp:1337"));
91   }
92 }
93 
94 TEST_CASE("doAssert") {
95   SECTION("does nothing if expression equals expected result") {
96     doAssert(
97         RC_INTERNAL_CAPTURE(true), true, CaseResult::Type::Failure, "", 0, "");
98   }
99 
100   prop(
101       "throws CaseResult of given type if expression does not equal expected "
102       "result",
__anoneeb93ac80202(CaseResult::Type type) 103       [](CaseResult::Type type) {
104         try {
105           doAssert(RC_INTERNAL_CAPTURE(true), false, type, "", 0, "");
106         } catch (const CaseResult &result) {
107           RC_SUCCEED_IF(result.type == type);
108         }
109         RC_FAIL("Did not throw");
110       });
111 }
112 
113 TEST_CASE("assertions") {
114   // We want to test that we never evaluate expression components more than once
115   // so we pass x++ as a component to test for that.
116   int x = 0;
117 
118   SECTION("RC_ASSERT") {
119     SECTION("does not throw if expression is true") { RC_ASSERT(100 == 100); }
120 
121     SECTION("when false, throws Failure with relevant info") {
122       try {
123         RC_ASSERT(x++ == 100);
124         FAIL("Never threw");
125       } catch (const CaseResult &result) {
126         REQUIRE(result.type == CaseResult::Type::Failure);
127         REQUIRE(descriptionContains(result, "0 == 100"));
128         REQUIRE(descriptionContains(result, "RC_ASSERT(x++ == 100)"));
129       }
130     }
131   }
132 
133   SECTION("RC_ASSERT_THROWS") {
134     SECTION("does not throw if expression throws") {
135       RC_ASSERT_THROWS(throw 0);
136     }
137 
138     SECTION("throws Failure with relevant info when expression does not throw") {
139       try {
140         RC_ASSERT_THROWS(x++);
141         FAIL("Never threw");
142       } catch (const CaseResult &result) {
143         REQUIRE(result.type == CaseResult::Type::Failure);
144         REQUIRE(descriptionContains(result, "RC_ASSERT_THROWS(x++)"));
145       }
146     }
147   }
148 
149   SECTION("RC_ASSERT_THROWS_AS") {
150     SECTION(
151         "does not throw if expression throws exception matching given type") {
152       // Intentionally different but matching types
153       RC_ASSERT_THROWS_AS(throw std::runtime_error("foo"), std::exception);
154     }
155 
156     SECTION(
157         "throws Failure with releveant info if expression throws exception "
158         "that does not match the provided type") {
159       try {
160         RC_ASSERT_THROWS_AS(throw x++, CaseResult);
161         FAIL("Never threw");
162       } catch (const CaseResult &result) {
163         REQUIRE(result.type == CaseResult::Type::Failure);
164         REQUIRE(descriptionContains(result, "RC_ASSERT_THROWS_AS(throw x++, CaseResult)"));
165         REQUIRE(descriptionContains(result, "did not match CaseResult"));
166       }
167     }
168 
169     SECTION(
170         "throws Failure with relevant info when expression does not throw") {
171       try {
172         RC_ASSERT_THROWS_AS(x++, int);
173         FAIL("Never threw");
174       } catch (const CaseResult &result) {
175         REQUIRE(result.type == CaseResult::Type::Failure);
176         REQUIRE(descriptionContains(result, "RC_ASSERT_THROWS_AS(x++, int)"));
177       }
178     }
179   }
180 
181   SECTION("RC_ASSERT_FALSE") {
182     SECTION("does not throw if expression is false") {
183       RC_ASSERT_FALSE(100 == 101);
184     }
185 
186     SECTION("when true, throws Failure with relevant info") {
187       try {
188         RC_ASSERT_FALSE(x++ == 0);
189         FAIL("Never threw");
190       } catch (const CaseResult &result) {
191         REQUIRE(result.type == CaseResult::Type::Failure);
192         REQUIRE(descriptionContains(result, "0 == 0"));
193         REQUIRE(descriptionContains(result, "RC_ASSERT_FALSE(x++ == 0)"));
194       }
195     }
196   }
197 
198   SECTION("RC_FAIL") {
199     SECTION("throws Failure with message") {
200       try {
201         RC_FAIL("foo bar baz");
202         FAIL("Never threw");
203       } catch (const CaseResult &result) {
204         REQUIRE(result.type == CaseResult::Type::Failure);
205         REQUIRE(descriptionContains(result, "RC_FAIL(\"foo bar baz\")"));
206       }
207     }
208 
209     SECTION("throws Failure with macro name only if no message") {
210       try {
211         RC_FAIL();
212         FAIL("Never threw");
213       } catch (const CaseResult &result) {
214         REQUIRE(result.type == CaseResult::Type::Failure);
215         REQUIRE(descriptionContains(result, "RC_FAIL()"));
216       }
217     }
218 
219     SECTION("message is only two lines if no arguments") {
220       try {
221         RC_FAIL();
222         FAIL("Never threw");
223       } catch (const CaseResult &result) {
224         REQUIRE(std::count(begin(result.description),
225                            end(result.description),
226                            '\n') == 1);
227       }
228     }
229   }
230 
231   SECTION("RC_SUCCEED_IF") {
232     SECTION("does not throw if expression is false") {
233       RC_SUCCEED_IF(100 == 101);
234     }
235 
236     SECTION("when true, throws Success with relevant info") {
237       try {
238         RC_SUCCEED_IF(x++ == 0);
239         FAIL("Never threw");
240       } catch (const CaseResult &result) {
241         REQUIRE(result.type == CaseResult::Type::Success);
242         REQUIRE(descriptionContains(result, "0 == 0"));
243         REQUIRE(descriptionContains(result, "RC_SUCCEED_IF(x++ == 0)"));
244       }
245     }
246   }
247 
248   SECTION("RC_SUCCEED") {
249     SECTION("throws Success with message") {
250       try {
251         RC_SUCCEED("foo bar baz");
252         FAIL("Never threw");
253       } catch (const CaseResult &result) {
254         REQUIRE(result.type == CaseResult::Type::Success);
255         REQUIRE(descriptionContains(result, "RC_SUCCEED(\"foo bar baz\")"));
256       }
257     }
258 
259     SECTION("throws Success with macro name only if no message") {
260       try {
261         RC_SUCCEED();
262         FAIL("Never threw");
263       } catch (const CaseResult &result) {
264         REQUIRE(result.type == CaseResult::Type::Success);
265         REQUIRE(descriptionContains(result, "RC_SUCCEED()"));
266       }
267     }
268 
269     SECTION("message is only two lines if no arguments") {
270       try {
271         RC_SUCCEED();
272         FAIL("Never threw");
273       } catch (const CaseResult &result) {
274         REQUIRE(std::count(begin(result.description),
275                            end(result.description),
276                            '\n') == 1);
277       }
278     }
279   }
280 
281   SECTION("RC_PRE") {
282     SECTION("does not throw if expression is true") { RC_PRE(100 == 100); }
283 
284     SECTION("when false, throws Discard with relevant info") {
285       try {
286         RC_PRE(x++ == 100);
287         FAIL("Never threw");
288       } catch (const CaseResult &result) {
289         REQUIRE(result.type == CaseResult::Type::Discard);
290         REQUIRE(descriptionContains(result, "0 == 100"));
291         REQUIRE(descriptionContains(result, "RC_PRE(x++ == 100)"));
292       }
293     }
294   }
295 
296   SECTION("RC_DISCARD") {
297     SECTION("throws Discard with message") {
298       try {
299         RC_DISCARD("foo bar baz");
300         FAIL("Never threw");
301       } catch (const CaseResult &result) {
302         REQUIRE(result.type == CaseResult::Type::Discard);
303         REQUIRE(descriptionContains(result, "RC_DISCARD(\"foo bar baz\")"));
304       }
305     }
306 
307     SECTION("throws Discard with macro name only if no message") {
308       try {
309         RC_DISCARD();
310         FAIL("Never threw");
311       } catch (const CaseResult &result) {
312         REQUIRE(result.type == CaseResult::Type::Discard);
313         REQUIRE(descriptionContains(result, "RC_DISCARD()"));
314       }
315     }
316 
317     SECTION("message is only two lines if no arguments") {
318       try {
319         RC_DISCARD();
320         FAIL("Never threw");
321       } catch (const CaseResult &result) {
322         REQUIRE(std::count(begin(result.description),
323                            end(result.description),
324                            '\n') == 1);
325       }
326     }
327   }
328 }
329