diff --git a/include/libimp/expected.h b/include/libimp/expected.h index 9c25da3..587ebd8 100644 --- a/include/libimp/expected.h +++ b/include/libimp/expected.h @@ -246,7 +246,8 @@ struct storage : value_getter, T, E> { storage(storage &&other) : getter_t(std::move(other)) - , has_value_(std::exchange(other.has_value_, false)) {} + /// After construction, has_value() is equal to other.has_value(). + , has_value_(other.has_value_) {} template storage(storage const &other) @@ -256,7 +257,8 @@ struct storage : value_getter, T, E> { template storage(storage &&other) : getter_t(std::move(other)) - , has_value_(std::exchange(other.has_value_, false)) {} + /// After construction, has_value() is equal to other.has_value(). + , has_value_(other.has_value_) {} bool has_value() const noexcept { return has_value_; @@ -331,7 +333,7 @@ class expected : public detail_expected::storage::typ expected() : detail_expected::storage(in_place) {} - + expected &operator=(expected other) { this->swap(other); return *this; diff --git a/test/imp/test_imp_expected.cpp b/test/imp/test_imp_expected.cpp new file mode 100644 index 0000000..21f6440 --- /dev/null +++ b/test/imp/test_imp_expected.cpp @@ -0,0 +1,146 @@ + +#include +#include +#include + +#include "gtest/gtest.h" + +#include "libimp/expected.h" + +namespace { + +class test_val { +public: + int val = 0; + int dc_ = 0; + int cc_ = 0; + int mv_ = 0; + + test_val() { + dc_ += 1; + std::printf("test_val construct.\n"); + } + test_val(test_val const &o) + : val(o.val) { + cc_ = o.cc_ + 1; + std::printf("test_val copy construct.\n"); + } + test_val(test_val &&o) noexcept + : val(std::exchange(o.val, 0)) { + mv_ = o.mv_ + 1; + std::printf("test_val move construct.\n"); + } + ~test_val() { + std::printf("test_val destruct.\n"); + } + + test_val &operator=(test_val &&o) noexcept { + mv_ = o.mv_ + 1; + val = std::exchange(o.val, 0); + return *this; + } + + test_val(int v) + : val(v) { + std::printf("test_val value initialization.\n"); + } + + bool operator==(test_val const &rhs) const { + return val == rhs.val; + } +}; + +class test_err { +public: + int dc_ = 0; + int cc_ = 0; + int mv_ = 0; + std::int64_t val = 0; + + test_err() { + dc_ += 1; + std::printf("test_err construct.\n"); + } + test_err(test_err const &o) + : val(o.val) { + cc_ = o.cc_ + 1; + std::printf("test_err copy construct.\n"); + } + test_err(test_err &&o) noexcept + : val(std::exchange(o.val, 0)) { + mv_ = o.mv_ + 1; + std::printf("test_err move construct.\n"); + } + ~test_err() { + std::printf("test_err destruct.\n"); + } + + test_err &operator=(test_err &&o) noexcept { + mv_ = o.mv_ + 1; + val = std::exchange(o.val, 0); + return *this; + } + + test_err(int v) + : val(v) { + std::printf("test_err value initialization.\n"); + } + + bool operator==(test_err const &rhs) const { + return val == rhs.val; + } +}; + +} // namespace + +TEST(expected, in_place) { + imp::expected e1; + EXPECT_TRUE(e1); + EXPECT_EQ(e1.value().dc_, 1); + EXPECT_EQ(e1.value().val, 0); + + imp::expected e2 {imp::in_place, 123}; + EXPECT_TRUE(e2); + EXPECT_EQ(e2.value().dc_, 0); + EXPECT_EQ(e2.value().val, 123); +} + +TEST(expected, unexpected) { + imp::expected e1 {imp::unexpected}; + EXPECT_FALSE(e1); + EXPECT_EQ(e1.error().dc_, 1); + EXPECT_EQ(e1.error().val, 0); + + imp::expected e2 {imp::unexpected, 321}; + EXPECT_FALSE(e2); + EXPECT_EQ(e2.error().dc_, 0); + EXPECT_EQ(e2.error().val, 321); +} + +TEST(expected, copy_and_move) { + imp::expected e1 {imp::in_place, 123}; + imp::expected e2 {e1}; + EXPECT_TRUE(e1); + EXPECT_TRUE(e2); + EXPECT_EQ(e1, e2); + EXPECT_EQ(e2.value().cc_, 1); + EXPECT_EQ(e2.value().val, 123); + + imp::expected e3 {imp::unexpected, 333}; + imp::expected e4 {e3}; + EXPECT_FALSE(e3); + EXPECT_FALSE(e4); + EXPECT_EQ(e3, e4); + EXPECT_EQ(e4.error().cc_, 1); + EXPECT_EQ(e4.error().val, 333); + + imp::expected e5; + e5 = e1; + EXPECT_EQ(e1, e5); + EXPECT_EQ(e5.value().val, 123); + + imp::expected e6; + e6 = std::move(e5); + EXPECT_EQ(e1, e6); + EXPECT_EQ(e5.value().val, 0); +} \ No newline at end of file