Brian Silverman | da86135 | 2019-02-02 16:42:28 -0800 | [diff] [blame] | 1 | #include "catch.hpp" |
| 2 | #include "optional.hpp" |
| 3 | |
| 4 | TEST_CASE("Noexcept", "[noexcept]") { |
| 5 | tl::optional<int> o1{4}; |
| 6 | tl::optional<int> o2{42}; |
| 7 | |
| 8 | SECTION("comparison with nullopt") { |
| 9 | REQUIRE(noexcept(o1 == tl::nullopt)); |
| 10 | REQUIRE(noexcept(tl::nullopt == o1)); |
| 11 | REQUIRE(noexcept(o1 != tl::nullopt)); |
| 12 | REQUIRE(noexcept(tl::nullopt != o1)); |
| 13 | REQUIRE(noexcept(o1 < tl::nullopt)); |
| 14 | REQUIRE(noexcept(tl::nullopt < o1)); |
| 15 | REQUIRE(noexcept(o1 <= tl::nullopt)); |
| 16 | REQUIRE(noexcept(tl::nullopt <= o1)); |
| 17 | REQUIRE(noexcept(o1 > tl::nullopt)); |
| 18 | REQUIRE(noexcept(tl::nullopt > o1)); |
| 19 | REQUIRE(noexcept(o1 >= tl::nullopt)); |
| 20 | REQUIRE(noexcept(tl::nullopt >= o1)); |
| 21 | } |
| 22 | |
| 23 | SECTION("swap") { |
| 24 | //TODO see why this fails |
| 25 | #if !defined(_MSC_VER) || _MSC_VER > 1900 |
| 26 | REQUIRE(noexcept(swap(o1, o2)) == noexcept(o1.swap(o2))); |
| 27 | |
| 28 | struct nothrow_swappable { |
| 29 | nothrow_swappable &swap(const nothrow_swappable &) noexcept { |
| 30 | return *this; |
| 31 | } |
| 32 | }; |
| 33 | |
| 34 | struct throw_swappable { |
| 35 | throw_swappable() = default; |
| 36 | throw_swappable(const throw_swappable &) {} |
| 37 | throw_swappable(throw_swappable &&) {} |
| 38 | throw_swappable &swap(const throw_swappable &) { return *this; } |
| 39 | }; |
| 40 | |
| 41 | tl::optional<nothrow_swappable> ont; |
| 42 | tl::optional<throw_swappable> ot; |
| 43 | |
| 44 | REQUIRE(noexcept(ont.swap(ont))); |
| 45 | REQUIRE(!noexcept(ot.swap(ot))); |
| 46 | #endif |
| 47 | } |
| 48 | |
| 49 | SECTION("constructors") { |
| 50 | //TODO see why this fails |
| 51 | #if !defined(_MSC_VER) || _MSC_VER > 1900 |
| 52 | REQUIRE(noexcept(tl::optional<int>{})); |
| 53 | REQUIRE(noexcept(tl::optional<int>{tl::nullopt})); |
| 54 | |
| 55 | struct nothrow_move { |
| 56 | nothrow_move(nothrow_move &&) noexcept = default; |
| 57 | }; |
| 58 | |
| 59 | struct throw_move { |
| 60 | throw_move(throw_move &&){}; |
| 61 | }; |
| 62 | |
| 63 | using nothrow_opt = tl::optional<nothrow_move>; |
| 64 | using throw_opt = tl::optional<throw_move>; |
| 65 | |
| 66 | REQUIRE(std::is_nothrow_move_constructible<nothrow_opt>::value); |
| 67 | REQUIRE(!std::is_nothrow_move_constructible<throw_opt>::value); |
| 68 | #endif |
| 69 | } |
| 70 | |
| 71 | SECTION("assignment") { |
| 72 | REQUIRE(noexcept(o1 = tl::nullopt)); |
| 73 | |
| 74 | struct nothrow_move_assign { |
| 75 | nothrow_move_assign() = default; |
| 76 | nothrow_move_assign(nothrow_move_assign &&) noexcept = default; |
| 77 | nothrow_move_assign &operator=(const nothrow_move_assign &) = default; |
| 78 | }; |
| 79 | |
| 80 | struct throw_move_assign { |
| 81 | throw_move_assign() = default; |
| 82 | throw_move_assign(throw_move_assign &&){}; |
| 83 | throw_move_assign &operator=(const throw_move_assign &) { return *this; } |
| 84 | }; |
| 85 | |
| 86 | using nothrow_opt = tl::optional<nothrow_move_assign>; |
| 87 | using throw_opt = tl::optional<throw_move_assign>; |
| 88 | |
| 89 | REQUIRE( |
| 90 | noexcept(std::declval<nothrow_opt>() = std::declval<nothrow_opt>())); |
| 91 | REQUIRE(!noexcept(std::declval<throw_opt>() = std::declval<throw_opt>())); |
| 92 | } |
| 93 | |
| 94 | SECTION("observers") { |
| 95 | REQUIRE(noexcept(static_cast<bool>(o1))); |
| 96 | REQUIRE(noexcept(o1.has_value())); |
| 97 | } |
| 98 | |
| 99 | SECTION("modifiers") { REQUIRE(noexcept(o1.reset())); } |
| 100 | } |