Skip to content

Commit 3971917

Browse files
committed
More unit tests for unexpected
1 parent 57291ca commit 3971917

File tree

1 file changed

+271
-21
lines changed

1 file changed

+271
-21
lines changed

tests/pfn/expected.cpp

Lines changed: 271 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
// Distributed under the ISC License. See accompanying file LICENSE.md
44
// or copy at https://opensource.org/licenses/ISC
55

6+
#include "catch2/catch_test_macros.hpp"
67
#include <pfn/expected.hpp>
78

89
#include <catch2/catch_all.hpp>
910

11+
#include <stdexcept>
1012
#include <type_traits>
1113

1214
enum Error { unknown, secret = 142, mystery = 176 };
@@ -131,8 +133,86 @@ TEST_CASE("unexpect", "[expected][polyfill][unexpect]")
131133
}
132134
}
133135

136+
namespace unxp {
137+
static int witness = 0;
138+
struct Foo {
139+
int v = {};
140+
141+
Foo() = delete;
142+
Foo(Foo &&) = default;
143+
144+
Foo &operator=(Foo &o) noexcept
145+
{
146+
v = o.v;
147+
witness *= 53;
148+
return *this;
149+
}
150+
151+
Foo &operator=(Foo const &o) noexcept
152+
{
153+
v = o.v;
154+
witness *= 59;
155+
return *this;
156+
}
157+
158+
Foo &operator=(Foo &&o) noexcept
159+
{
160+
v = o.v;
161+
witness *= 61;
162+
return *this;
163+
}
164+
165+
Foo &operator=(Foo const &&o) noexcept
166+
{
167+
v = o.v;
168+
witness *= 67;
169+
return *this;
170+
}
171+
172+
Foo(int a) noexcept : v(a) { witness += a; }
173+
174+
Foo(auto &&...a) noexcept
175+
requires(sizeof...(a) > 1 && (std::is_same_v<std::remove_cvref_t<decltype(a)>, int> && ...))
176+
: v((1 * ... * a))
177+
{
178+
witness += v;
179+
}
180+
181+
Foo(std::initializer_list<double> l, auto... a) noexcept(false)
182+
requires(std::is_same_v<std::remove_cvref_t<decltype(a)>, int> && ...)
183+
: v(init(l, a...))
184+
{
185+
witness += v;
186+
}
187+
188+
bool operator==(Foo const &) const noexcept = default;
189+
190+
static int init(std::initializer_list<double> l, auto &&...a) noexcept(false)
191+
{
192+
double ret = (1 * ... * a);
193+
for (auto d : l) {
194+
if (d == 0.0)
195+
throw std::runtime_error("invalid input");
196+
ret *= d;
197+
}
198+
return static_cast<int>(ret);
199+
}
200+
};
201+
202+
void swap(Foo &l, Foo &r)
203+
{
204+
std::swap(l.v, r.v);
205+
witness *= 97;
206+
}
207+
208+
} // namespace unxp
209+
134210
TEST_CASE("unexpected", "[expected][polyfill][unexpected]")
135211
{
212+
using pfn::unexpected;
213+
using unxp::Foo;
214+
using unxp::witness;
215+
136216
SECTION("is_valid_unexpected")
137217
{
138218
using pfn::detail::_is_valid_unexpected;
@@ -156,39 +236,209 @@ TEST_CASE("unexpected", "[expected][polyfill][unexpected]")
156236

157237
SECTION("constructors")
158238
{
159-
using pfn::unexpected;
239+
SECTION("constexpr, CTAD")
240+
{
241+
constexpr unexpected c{Error::mystery};
242+
static_assert(c.error() == Error::mystery);
243+
static_assert(std::is_same_v<decltype(c), unexpected<Error> const>);
244+
static_assert(std::is_nothrow_constructible_v<decltype(c), Error>);
245+
SUCCEED();
246+
}
160247

161-
SECTION("explicit single parameter")
248+
SECTION("constexpr, no CTAD")
162249
{
163-
SECTION("constexpr, CTAD")
164-
{
165-
constexpr unexpected c1{Error::mystery};
166-
static_assert(std::is_same_v<decltype(c1), unexpected<Error> const>);
167-
static_assert(c1.error() == Error::mystery);
168-
}
250+
constexpr unexpected<int> c{42};
251+
static_assert(c.error() == 42);
252+
static_assert(std::is_nothrow_constructible_v<decltype(c), int>);
253+
SUCCEED();
254+
}
255+
256+
SECTION("no conversion, CTAD")
257+
{
258+
auto const before = witness;
259+
unexpected c{Foo{2}};
260+
CHECK(witness == before + 2);
261+
CHECK(c.error() == Foo{2});
262+
CHECK(c == unexpected<Foo>{2});
263+
static_assert(std::is_same_v<decltype(c), unexpected<Foo>>);
264+
static_assert(std::is_nothrow_constructible_v<decltype(c), Foo>);
265+
}
266+
267+
SECTION("conversion, no CTAD")
268+
{
269+
auto const before = witness;
270+
unexpected<Foo> c(3);
271+
CHECK(witness == before + 3);
272+
CHECK(c.error().v == 3);
273+
CHECK(c == unexpected<Foo>{3});
274+
static_assert(std::is_nothrow_constructible_v<decltype(c), int>);
275+
}
169276

170-
SECTION("constexpr, no CTAD")
277+
SECTION("in-place, no CTAD")
278+
{
279+
auto const before = witness;
280+
unexpected<Foo> c(std::in_place, 3, 5);
281+
CHECK(witness == before + 3 * 5);
282+
CHECK(c.error() == Foo{3, 5});
283+
CHECK(c == unexpected<Foo>{15});
284+
static_assert(std::is_nothrow_constructible_v<decltype(c), std::in_place_t, int, int>);
285+
}
286+
287+
SECTION("in_place, not CTAD, initializer_list, noexcept(false)")
288+
{
289+
SECTION("forwarded args")
171290
{
172-
constexpr unexpected<int> c1{42};
173-
static_assert(std::is_same_v<decltype(c1), unexpected<int> const>);
174-
static_assert(c1.error() == 42);
291+
auto const before = witness;
292+
unexpected<Foo> c(std::in_place, {3.0, 5.0}, 7, 11);
293+
auto const d = 3 * 5 * 7 * 11;
294+
CHECK(witness == before + d);
295+
CHECK(c.error() == Foo{d});
296+
CHECK(c == unexpected{Foo{d}});
297+
static_assert(
298+
not std::is_nothrow_constructible_v<decltype(c), std::in_place_t, std::initializer_list<double>, int, int>);
299+
static_assert(std::is_constructible_v<decltype(c), std::in_place_t, std::initializer_list<double>, int, int>);
175300
}
176301

177-
SECTION("no conversion, CTAD")
302+
SECTION("no forwarded args")
178303
{
179-
unexpected const c2{Error::secret};
180-
static_assert(std::is_same_v<decltype(c2), unexpected<Error> const>);
181-
CHECK(c2.error() == Error::secret);
304+
auto const before = witness;
305+
unexpected<Foo> c(std::in_place, {2.0, 2.5});
306+
CHECK(witness == before + 5);
307+
CHECK(c.error() == Foo{5});
308+
CHECK(c == unexpected<Foo>{5});
309+
static_assert(not std::is_nothrow_constructible_v<decltype(c), std::in_place_t, std::initializer_list<double>>);
310+
static_assert(std::is_constructible_v<decltype(c), std::in_place_t, std::initializer_list<double>>);
182311
}
183312

184-
SECTION("conversion, no CTAD")
313+
SECTION("exception thrown")
185314
{
186-
unexpected<double> c3(12);
187-
static_assert(std::is_same_v<decltype(c3), unexpected<double>>);
188-
CHECK(c3.error() == 12.0);
315+
unexpected<Foo> t{13};
316+
auto const before = witness;
317+
try {
318+
t = unexpected<Foo>{std::in_place, {2.0, 1.0, 0.0}, 5};
319+
FAIL();
320+
} catch (std::runtime_error const &) {
321+
SUCCEED();
322+
}
323+
CHECK(t.error().v == 13);
324+
CHECK(witness == before);
189325
}
190326
}
327+
}
191328

192-
SECTION("in_place") {}
329+
SECTION("accessor")
330+
{
331+
Foo v{1};
332+
333+
SECTION("lval")
334+
{
335+
unexpected<Foo> t{13};
336+
auto before = witness;
337+
v = t.error();
338+
CHECK(witness == before * 53);
339+
CHECK(v == Foo{13});
340+
}
341+
342+
SECTION("lval const")
343+
{
344+
unexpected<Foo> const t{17};
345+
auto before = witness;
346+
v = t.error();
347+
CHECK(witness == before * 59);
348+
CHECK(v == Foo{17});
349+
}
350+
351+
SECTION("rval")
352+
{
353+
unexpected<Foo> t{19};
354+
auto before = witness;
355+
v = std::move(t.error());
356+
CHECK(witness == before * 61);
357+
CHECK(v == Foo{19});
358+
}
359+
360+
SECTION("rval const")
361+
{
362+
unexpected<Foo> const t{23};
363+
auto before = witness;
364+
v = std::move(t.error());
365+
CHECK(witness == before * 67);
366+
CHECK(v == Foo{23});
367+
}
368+
}
369+
370+
SECTION("assignment")
371+
{
372+
unexpected<Foo> v{0};
373+
374+
SECTION("lval")
375+
{
376+
unexpected<Foo> t{13};
377+
auto before = witness;
378+
v = t; // t binds to unexpected<Foo> const &
379+
CHECK(witness == before * 59);
380+
CHECK(v.error() == Foo{13});
381+
}
382+
383+
SECTION("lval const")
384+
{
385+
unexpected<Foo> const t{17};
386+
auto before = witness;
387+
v = t; // t binds to unexpected<Foo> const &
388+
CHECK(witness == before * 59);
389+
CHECK(v.error() == Foo{17});
390+
}
391+
392+
SECTION("rval")
393+
{
394+
unexpected<Foo> t{19};
395+
auto before = witness;
396+
v = std::move(t); // t binds to unexpected<Foo> &&
397+
CHECK(witness == before * 61);
398+
CHECK(v.error() == Foo{19});
399+
}
400+
401+
SECTION("rval const")
402+
{
403+
unexpected<Foo> const t{23};
404+
auto before = witness;
405+
v = std::move(t); // t binds to unexpected<Foo> const &
406+
CHECK(witness == before * 59);
407+
CHECK(v.error() == Foo{23});
408+
}
409+
}
410+
411+
SECTION("swap")
412+
{
413+
unexpected<Foo> v{2};
414+
unexpected w{Foo{3}};
415+
auto before = witness;
416+
v.swap(w);
417+
CHECK(witness == before * 97);
418+
CHECK(v == unexpected{Foo{3}});
419+
CHECK(w == unexpected{Foo{2}});
420+
w.error() = Foo{11};
421+
before = witness;
422+
swap(v, w);
423+
CHECK(v.error() == Foo{11});
424+
CHECK(w.error() == Foo(3));
425+
}
426+
427+
SECTION("constexpr all, CTAD")
428+
{
429+
constexpr auto test = [](auto i) constexpr {
430+
unexpected a{i};
431+
unexpected b{i * 5};
432+
swap(a, b);
433+
unexpected c{0};
434+
c = b;
435+
b.swap(c);
436+
return unexpected{b.error() * a.error() * 7};
437+
};
438+
constexpr auto c = test(21);
439+
static_assert(std::is_same_v<decltype(c), unexpected<int> const>);
440+
static_assert(c.error() == 21 * 21 * 5 * 7);
441+
442+
SUCCEED();
193443
}
194444
}

0 commit comments

Comments
 (0)