|
| 1 | +// compat.tl-optional — assert value/empty state, observers, mutation, monadic |
| 2 | +// chaining, reference binding, and constexpr construction through the public |
| 3 | +// header. The test uses only the standard library in addition to tl/optional. |
| 4 | +#include <tl/optional.hpp> |
| 5 | + |
| 6 | +#include <cstdio> |
| 7 | +#include <string> |
| 8 | +#include <type_traits> |
| 9 | + |
| 10 | +int main() { |
| 11 | + bool ok = true; |
| 12 | + auto check = [&](bool condition, const char* what) { |
| 13 | + if (!condition) { |
| 14 | + std::printf("FAIL: %s\n", what); |
| 15 | + ok = false; |
| 16 | + } |
| 17 | + }; |
| 18 | + |
| 19 | + tl::optional<int> value = tl::make_optional(42); |
| 20 | + tl::optional<int> empty = tl::nullopt; |
| 21 | + check(value.has_value() && *value == 42, "value construction and observer"); |
| 22 | + check(!empty.has_value(), "nullopt constructs an empty optional"); |
| 23 | + check(value.value_or(7) == 42 && empty.value_or(7) == 7, |
| 24 | + "value_or handles both states"); |
| 25 | + |
| 26 | + constexpr tl::optional<int> constexpr_value = tl::make_optional(11); |
| 27 | + static_assert(constexpr_value.has_value(), "constexpr optional"); |
| 28 | + |
| 29 | + value.reset(); |
| 30 | + check(!value, "reset clears the value"); |
| 31 | + value.emplace(21); |
| 32 | + check(value && *value == 21, "emplace constructs a new value"); |
| 33 | + |
| 34 | + const auto doubled = empty.map([](int x) { return x * 2; }); |
| 35 | + check(!doubled, "map on an empty optional stays empty"); |
| 36 | + const auto mapped = tl::make_optional(21).map([](int x) { return x * 2; }); |
| 37 | + check(mapped && *mapped == 42, "map transforms a present value"); |
| 38 | + |
| 39 | + const auto chained = tl::make_optional(5).and_then([](int x) { |
| 40 | + return tl::make_optional(x * 3); |
| 41 | + }); |
| 42 | + check(chained && *chained == 15, "and_then chains optional-producing calls"); |
| 43 | + |
| 44 | + const auto fallback = empty.or_else([] { return tl::make_optional(13); }); |
| 45 | + check(fallback && *fallback == 13, "or_else supplies a fallback"); |
| 46 | + check(tl::make_optional(42).map_or([](int x) { return x + 1; }, 0) == 43, |
| 47 | + "map_or applies the mapper when present"); |
| 48 | + check(empty.map_or([](int x) { return x + 1; }, 0) == 0, |
| 49 | + "map_or returns the fallback when empty"); |
| 50 | + |
| 51 | + int first = 1; |
| 52 | + int second = 2; |
| 53 | + tl::optional<int&> reference = first; |
| 54 | + check(&*reference == &first, "reference optional binds the original object"); |
| 55 | + reference = second; |
| 56 | + check(&*reference == &second, "assignment rebinds the reference"); |
| 57 | + *reference = 9; |
| 58 | + check(second == 9, "writing through a reference optional mutates the object"); |
| 59 | + |
| 60 | + tl::optional<std::string> text = std::string("hello"); |
| 61 | + auto taken = text.take(); |
| 62 | + check(taken && *taken == "hello" && !text, |
| 63 | + "take moves out the value and empties the source"); |
| 64 | + |
| 65 | + static_assert(std::is_same<decltype(tl::make_optional<int&>(first)), |
| 66 | + tl::optional<int&>>::value, |
| 67 | + "make_optional preserves reference optionals"); |
| 68 | + |
| 69 | + if (ok) { |
| 70 | + std::puts("tl-optional OK"); |
| 71 | + } |
| 72 | + return ok ? 0 : 1; |
| 73 | +} |
0 commit comments