diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/maybe_ut.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/maybe_ut.cpp')
-rw-r--r-- | util/generic/maybe_ut.cpp | 1006 |
1 files changed, 1006 insertions, 0 deletions
diff --git a/util/generic/maybe_ut.cpp b/util/generic/maybe_ut.cpp new file mode 100644 index 0000000000..2c1a425c5e --- /dev/null +++ b/util/generic/maybe_ut.cpp @@ -0,0 +1,1006 @@ +#include <util/generic/string.h> +#include <util/generic/vector.h> +#include <util/stream/str.h> +#include <library/cpp/testing/unittest/registar.h> + +#include "maybe.h" + +class TIncrementOnDestroy { +private: + int* Ptr_; + +public: + TIncrementOnDestroy(int* ptr) noexcept + : Ptr_(ptr) + { + } + + ~TIncrementOnDestroy() { + ++*Ptr_; + } +}; + +Y_UNIT_TEST_SUITE(TMaybeTest) { + Y_UNIT_TEST(TestStatic) { + using T1 = TMaybe<int>; + static_assert(std::is_trivially_copy_constructible<T1>::value, ""); + static_assert(std::is_trivially_destructible<T1>::value, ""); + + using T2 = TMaybe<TString*>; + static_assert(std::is_trivially_copy_constructible<T2>::value, ""); + static_assert(std::is_trivially_destructible<T2>::value, ""); + + using T3 = TMaybe<TMaybe<double>>; + static_assert(std::is_trivially_copy_constructible<T3>::value, ""); + static_assert(std::is_trivially_destructible<T3>::value, ""); + + using T4 = TMaybe<TString>; + static_assert(!std::is_trivially_copy_constructible<T4>::value, ""); + static_assert(!std::is_trivially_destructible<T4>::value, ""); + } + + Y_UNIT_TEST(TestWarning) { + TMaybe<size_t> x; + TStringStream ss; + TString line; + + while (ss.ReadLine(line)) { + x = line.size(); + } + + if (x == 5u) { + ss << "5\n"; + } + } + + Y_UNIT_TEST(TTestConstructorDestructor) { + int a = 0; + int b = 0; + + TMaybe<TIncrementOnDestroy>(); + UNIT_ASSERT_VALUES_EQUAL(a, b); + + TMaybe<TIncrementOnDestroy>(TIncrementOnDestroy(&a)); + b += 2; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + { + TMaybe<TIncrementOnDestroy> m1 = TIncrementOnDestroy(&a); + b += 1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + TMaybe<TIncrementOnDestroy> m2 = m1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + TMaybe<TIncrementOnDestroy> m3; + m3 = m1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + } + + b += 3; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + { + TMaybe<TIncrementOnDestroy> m4 = TIncrementOnDestroy(&a); + b += 1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + m4 = TIncrementOnDestroy(&a); + b += 1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + m4.Clear(); + b += 1; + UNIT_ASSERT_VALUES_EQUAL(a, b); + + m4.Clear(); + UNIT_ASSERT_VALUES_EQUAL(a, b); + } + } + + Y_UNIT_TEST(TestAssignmentClear) { + TMaybe<int> m5; + UNIT_ASSERT(!m5.Defined()); + UNIT_ASSERT(m5.Empty()); + UNIT_ASSERT(m5 == TMaybe<int>()); + UNIT_ASSERT(m5 == Nothing()); + UNIT_ASSERT(m5 != TMaybe<int>(4)); + + m5 = 4; + + UNIT_ASSERT(m5.Defined()); + UNIT_ASSERT(!m5.Empty()); + + UNIT_ASSERT_VALUES_EQUAL(4, m5.GetRef()); + UNIT_ASSERT(m5 == TMaybe<int>(4)); + UNIT_ASSERT(m5 != TMaybe<int>(3)); + UNIT_ASSERT(m5 != TMaybe<int>()); + UNIT_ASSERT(m5 != Nothing()); + + m5 = TMaybe<int>(5); + UNIT_ASSERT(m5.Defined()); + UNIT_ASSERT_VALUES_EQUAL(5, m5.GetRef()); + UNIT_ASSERT(m5 == TMaybe<int>(5)); + UNIT_ASSERT(m5 != TMaybe<int>(4)); + + m5 = TMaybe<int>(); + UNIT_ASSERT(m5.Empty()); + UNIT_ASSERT(m5 == TMaybe<int>()); + UNIT_ASSERT(m5 == Nothing()); + UNIT_ASSERT(m5 != TMaybe<int>(5)); + + m5 = 4; + m5 = Nothing(); + + UNIT_ASSERT(m5.Empty()); + UNIT_ASSERT(m5 == TMaybe<int>()); + UNIT_ASSERT(m5 == Nothing()); + UNIT_ASSERT(m5 != TMaybe<int>(5)); + + m5 = {}; + UNIT_ASSERT(m5.Empty()); + } + + Y_UNIT_TEST(TestInPlace) { + TMaybe<int> m; + + UNIT_ASSERT(!m); + + m.ConstructInPlace(1); + + UNIT_ASSERT(m == 1); + + auto& x = m.ConstructInPlace(2); + + UNIT_ASSERT(m == 2); + x = 7; + UNIT_ASSERT(m == 7); + } + + Y_UNIT_TEST(TestMove) { + struct TMovable { + int Flag = 0; + + TMovable(int flag) + : Flag(flag) + { + } + + TMovable(const TMovable&) = delete; + TMovable& operator=(const TMovable&) = delete; + + TMovable(TMovable&& other) { + std::swap(Flag, other.Flag); + } + TMovable& operator=(TMovable&& other) { + std::swap(Flag, other.Flag); + return *this; + } + }; + + // Move ctor from value + TMovable value1(1); + TMaybe<TMovable> m1(std::move(value1)); + UNIT_ASSERT(m1.Defined()); + UNIT_ASSERT_VALUES_EQUAL(m1->Flag, 1); + + // Move assignment from value + TMovable value2(2); + TMaybe<TMovable> m2; + m2 = std::move(value2); + UNIT_ASSERT(m2.Defined()); + UNIT_ASSERT_VALUES_EQUAL(m2->Flag, 2); + + // Move ctor from maybe + TMaybe<TMovable> m3(std::move(m1)); + UNIT_ASSERT(m3.Defined()); + UNIT_ASSERT_VALUES_EQUAL(m3->Flag, 1); + + // Move assignment from maybe + TMaybe<TMovable> m4; + m4 = std::move(m2); + UNIT_ASSERT(m4.Defined()); + UNIT_ASSERT_VALUES_EQUAL(m4->Flag, 2); + + // Move value from temporary maybe instance + TMovable o5 = *MakeMaybe<TMovable>(5); + UNIT_ASSERT_VALUES_EQUAL(o5.Flag, 5); + TMovable o6 = MakeMaybe<TMovable>(6).GetRef(); + UNIT_ASSERT_VALUES_EQUAL(o6.Flag, 6); + } + + Y_UNIT_TEST(TestCast) { + // Undefined maybe casts to undefined maybe + TMaybe<short> shortMaybe; + const auto undefinedMaybe = shortMaybe.Cast<long>(); + UNIT_ASSERT(!undefinedMaybe.Defined()); + + // Defined maybe casts to defined maybe of another type + shortMaybe = 34; + const auto longMaybe = shortMaybe.Cast<long>(); + UNIT_ASSERT(longMaybe.Defined()); + UNIT_ASSERT_VALUES_EQUAL(34, longMaybe.GetRef()); + } + + Y_UNIT_TEST(TestGetOr) { + UNIT_ASSERT_VALUES_EQUAL(TMaybe<TString>().GetOrElse("xxx"), TString("xxx")); + UNIT_ASSERT_VALUES_EQUAL(TMaybe<TString>("yyy").GetOrElse("xxx"), TString("yyy")); + + { + TString xxx = "xxx"; + UNIT_ASSERT_VALUES_EQUAL(TMaybe<TString>().GetOrElse(xxx).append('x'), TString("xxxx")); + UNIT_ASSERT_VALUES_EQUAL(xxx, "xxxx"); + } + + { + TString xxx = "xxx"; + UNIT_ASSERT_VALUES_EQUAL(TMaybe<TString>("yyy").GetOrElse(xxx).append('x'), TString("yyyx")); + UNIT_ASSERT_VALUES_EQUAL(xxx, "xxx"); + } + } + + /* + == + != + < + <= + > + >= +*/ + + Y_UNIT_TEST(TestCompareEqualEmpty) { + TMaybe<int> m1; + TMaybe<int> m2; + + UNIT_ASSERT(m1 == m2); + UNIT_ASSERT(!(m1 != m2)); + UNIT_ASSERT(!(m1 < m2)); + UNIT_ASSERT(m1 <= m2); + UNIT_ASSERT(!(m1 > m2)); + UNIT_ASSERT(m1 >= m2); + } + + Y_UNIT_TEST(TestCompareEqualNonEmpty) { + TMaybe<int> m1{1}; + TMaybe<int> m2{1}; + + UNIT_ASSERT(m1 == m2); + UNIT_ASSERT(!(m1 != m2)); + UNIT_ASSERT(!(m1 < m2)); + UNIT_ASSERT(m1 <= m2); + UNIT_ASSERT(!(m1 > m2)); + UNIT_ASSERT(m1 >= m2); + } + + Y_UNIT_TEST(TestCompareOneLessThanOther) { + TMaybe<int> m1{1}; + TMaybe<int> m2{2}; + + UNIT_ASSERT(!(m1 == m2)); + UNIT_ASSERT(m1 != m2); + UNIT_ASSERT(m1 < m2); + UNIT_ASSERT(m1 <= m2); + UNIT_ASSERT(!(m1 > m2)); + UNIT_ASSERT(!(m1 >= m2)); + } + + Y_UNIT_TEST(TestCompareTMaybeAndT_Equal) { + TMaybe<int> m{1}; + int v{1}; + + UNIT_ASSERT(m == v); + UNIT_ASSERT(!(m != v)); + UNIT_ASSERT(!(m < v)); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(m >= v); + + UNIT_ASSERT(v == m); + UNIT_ASSERT(!(v != m)); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(v <= m); + UNIT_ASSERT(!(v > m)); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestCompareTMaybeAndT_TMaybeLessThanT) { + TMaybe<int> m{1}; + int v{2}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(m < v); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(!(m >= v)); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(!(v <= m)); + UNIT_ASSERT(v > m); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestCompareTMaybeAndT_TMaybeGreaterThanT) { + TMaybe<int> m{2}; + int v{1}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(!(m < v)); + UNIT_ASSERT(!(m <= v)); + UNIT_ASSERT(m > v); + UNIT_ASSERT(m >= v); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(v < m); + UNIT_ASSERT(v <= m); + UNIT_ASSERT(!(v > m)); + UNIT_ASSERT(!(v >= m)); + } + + Y_UNIT_TEST(TestCompareEmptyTMaybeAndT) { + TMaybe<int> m; + int v{1}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(m < v); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(!(m >= v)); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(!(v <= m)); + UNIT_ASSERT(v > m); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestCompareEmptyTMaybeAndNothing) { + TMaybe<int> m; + auto n = Nothing(); + + UNIT_ASSERT(m == n); + UNIT_ASSERT(!(m != n)); + UNIT_ASSERT(!(m < n)); + UNIT_ASSERT(m <= n); + UNIT_ASSERT(!(m > n)); + UNIT_ASSERT(m >= n); + + UNIT_ASSERT(n == m); + UNIT_ASSERT(!(n != m)); + UNIT_ASSERT(!(n < m)); + UNIT_ASSERT(n <= m); + UNIT_ASSERT(!(n > m)); + UNIT_ASSERT(n >= m); + } + + Y_UNIT_TEST(TestCompareNonEmptyTMaybeAndNothing) { + TMaybe<int> m{1}; + auto n = Nothing(); + + UNIT_ASSERT(!(m == n)); + UNIT_ASSERT(m != n); + UNIT_ASSERT(!(m < n)); + UNIT_ASSERT(!(m <= n)); + UNIT_ASSERT(m > n); + UNIT_ASSERT(m >= n); + + UNIT_ASSERT(!(n == m)); + UNIT_ASSERT(n != m); + UNIT_ASSERT(n < m); + UNIT_ASSERT(n <= m); + UNIT_ASSERT(!(n > m)); + UNIT_ASSERT(!(n >= m)); + } + + Y_UNIT_TEST(TestCompareTMaybeAndConvertibleT_Equal) { + TMaybe<size_t> m{1}; + unsigned int v{1}; + + UNIT_ASSERT(m == v); + UNIT_ASSERT(!(m != v)); + UNIT_ASSERT(!(m < v)); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(m >= v); + + UNIT_ASSERT(v == m); + UNIT_ASSERT(!(v != m)); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(v <= m); + UNIT_ASSERT(!(v > m)); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestCompareTMaybeAndConvertibleT_TMaybeLessThanT) { + TMaybe<size_t> m{1}; + unsigned int v{2}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(m < v); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(!(m >= v)); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(!(v <= m)); + UNIT_ASSERT(v > m); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestCompareTMaybeAndConvertibleT_TMaybeGreaterThanT) { + TMaybe<size_t> m{2}; + unsigned int v{1}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(!(m < v)); + UNIT_ASSERT(!(m <= v)); + UNIT_ASSERT(m > v); + UNIT_ASSERT(m >= v); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(v < m); + UNIT_ASSERT(v <= m); + UNIT_ASSERT(!(v > m)); + UNIT_ASSERT(!(v >= m)); + } + + Y_UNIT_TEST(TestCompareEmptyTMaybeAndConvertibleT) { + TMaybe<size_t> m; + unsigned int v{1}; + + UNIT_ASSERT(!(m == v)); + UNIT_ASSERT(m != v); + UNIT_ASSERT(m < v); + UNIT_ASSERT(m <= v); + UNIT_ASSERT(!(m > v)); + UNIT_ASSERT(!(m >= v)); + + UNIT_ASSERT(!(v == m)); + UNIT_ASSERT(v != m); + UNIT_ASSERT(!(v < m)); + UNIT_ASSERT(!(v <= m)); + UNIT_ASSERT(v > m); + UNIT_ASSERT(v >= m); + } + + Y_UNIT_TEST(TestMakeMaybe) { + { + auto m1 = MakeMaybe<int>(1); + UNIT_ASSERT(*m1 == 1); + } + + { + struct TMockClass { + TMockClass(int i) + : I_(i) + { + } + + TMockClass(const TMockClass& other) + : I_(other.I_) + { + IsCopyConstructorCalled_ = true; + } + + TMockClass& operator=(const TMockClass& other) { + if (this != &other) { + I_ = other.I_; + IsCopyAssignmentOperatorCalled_ = true; + } + + return *this; + } + + TMockClass(TMockClass&& other) + : I_(other.I_) + { + IsMoveConstructorCalled_ = true; + } + + TMockClass& operator=(TMockClass&& other) { + if (this != &other) { + I_ = other.I_; + IsMoveAssignmentOperatorCalled_ = true; + } + + return *this; + } + + int I_; + bool IsCopyConstructorCalled_{false}; + bool IsMoveConstructorCalled_{false}; + bool IsCopyAssignmentOperatorCalled_{false}; + bool IsMoveAssignmentOperatorCalled_{false}; + }; + + auto m2 = MakeMaybe<TMockClass>(1); + UNIT_ASSERT(m2->I_ == 1); + UNIT_ASSERT(!m2->IsCopyConstructorCalled_); + UNIT_ASSERT(!m2->IsMoveConstructorCalled_); + UNIT_ASSERT(!m2->IsCopyAssignmentOperatorCalled_); + UNIT_ASSERT(!m2->IsMoveAssignmentOperatorCalled_); + } + + { + auto m3 = MakeMaybe<TVector<int>>({1, 2, 3, 4, 5}); + UNIT_ASSERT(m3->size() == 5); + UNIT_ASSERT(m3->at(0) == 1); + UNIT_ASSERT(m3->at(1) == 2); + UNIT_ASSERT(m3->at(2) == 3); + UNIT_ASSERT(m3->at(3) == 4); + UNIT_ASSERT(m3->at(4) == 5); + } + + { + struct TMockStruct4 { + TMockStruct4(int a, int b, int c) + : A_(a) + , B_(b) + , C_(c) + { + } + + int A_; + int B_; + int C_; + }; + + auto m4 = MakeMaybe<TMockStruct4>(1, 2, 3); + UNIT_ASSERT(m4->A_ == 1); + UNIT_ASSERT(m4->B_ == 2); + UNIT_ASSERT(m4->C_ == 3); + } + + { + struct TMockStruct5 { + TMockStruct5(const TVector<int>& vec, bool someFlag) + : Vec_(vec) + , SomeFlag_(someFlag) + { + } + + TVector<int> Vec_; + bool SomeFlag_; + }; + + auto m5 = MakeMaybe<TMockStruct5>({1, 2, 3}, true); + UNIT_ASSERT(m5->Vec_.size() == 3); + UNIT_ASSERT(m5->Vec_[0] == 1); + UNIT_ASSERT(m5->Vec_[1] == 2); + UNIT_ASSERT(m5->Vec_[2] == 3); + UNIT_ASSERT(m5->SomeFlag_); + } + } + + Y_UNIT_TEST(TestSwappingUsingMemberSwap) { + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = 2; + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(*m2 == 2); + + m1.Swap(m2); + + UNIT_ASSERT(*m1 == 2); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = Nothing(); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + + m1.Swap(m2); + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = Nothing(); + TMaybe<int> m2 = 1; + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + + m1.Swap(m2); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + } + } + + Y_UNIT_TEST(TestSwappingUsingMemberLittleSwap) { + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = 2; + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(*m2 == 2); + + m1.swap(m2); + + UNIT_ASSERT(*m1 == 2); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = Nothing(); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + + m1.swap(m2); + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = Nothing(); + TMaybe<int> m2 = 1; + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + + m1.swap(m2); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + } + } + + Y_UNIT_TEST(TestSwappingUsingGlobalSwap) { + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = 2; + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(*m2 == 2); + + ::Swap(m1, m2); + + UNIT_ASSERT(*m1 == 2); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = Nothing(); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + + ::Swap(m1, m2); + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = Nothing(); + TMaybe<int> m2 = 1; + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + + ::Swap(m1, m2); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + } + } + + Y_UNIT_TEST(TestSwappingUsingGlobalDoSwap) { + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = 2; + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(*m2 == 2); + + ::DoSwap(m1, m2); + + UNIT_ASSERT(*m1 == 2); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = Nothing(); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + + ::DoSwap(m1, m2); + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = Nothing(); + TMaybe<int> m2 = 1; + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + + ::DoSwap(m1, m2); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + } + } + + Y_UNIT_TEST(TestSwappingUsingStdSwap) { + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = 2; + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(*m2 == 2); + + ::std::swap(m1, m2); + + UNIT_ASSERT(*m1 == 2); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = 1; + TMaybe<int> m2 = Nothing(); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + + ::std::swap(m1, m2); + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + } + + { + TMaybe<int> m1 = Nothing(); + TMaybe<int> m2 = 1; + + UNIT_ASSERT(m1 == Nothing()); + UNIT_ASSERT(*m2 == 1); + + ::std::swap(m1, m2); + + UNIT_ASSERT(*m1 == 1); + UNIT_ASSERT(m2 == Nothing()); + } + } + + Y_UNIT_TEST(TestOutputStreamEmptyMaybe) { + TString s; + TStringOutput output(s); + output << TMaybe<int>(); + UNIT_ASSERT_EQUAL("(empty maybe)", s); + } + + Y_UNIT_TEST(TestOutputStreamNothing) { + TString s; + TStringOutput output(s); + output << Nothing(); + UNIT_ASSERT_VALUES_EQUAL("(empty maybe)", s); + } + + Y_UNIT_TEST(TestOutputStreamDefinedMaybe) { + TString s; + TStringOutput output(s); + output << TMaybe<int>(42); + UNIT_ASSERT_EQUAL("42", s); + } + + Y_UNIT_TEST(TestMaybeCovarianceImplicit) { + struct TestStruct { + TestStruct(int value) + : Value_(value) + { + } + + operator int() const { + return Value_; + } + + static TMaybe<int> Unwrap(TMaybe<TestStruct> testStructMaybe) { + return testStructMaybe; + } + + int Value_; + }; + + TMaybe<int> testMaybeFull = TestStruct::Unwrap(TMaybe<int>(42)); + UNIT_ASSERT(testMaybeFull.Defined()); + UNIT_ASSERT_EQUAL(testMaybeFull.GetRef(), 42); + + TMaybe<int> testMaybeEmpty = TestStruct::Unwrap(TMaybe<int>()); + UNIT_ASSERT(!testMaybeEmpty.Defined()); + } + + Y_UNIT_TEST(TestMaybeCovarianceExplicit) { + struct TestStruct { + explicit TestStruct(int value) + : Value_(value) + { + } + int Value_; + }; + + TMaybe<TestStruct> testStructMaybeFull(TMaybe<int>(42)); + UNIT_ASSERT(testStructMaybeFull.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybeFull.GetRef().Value_, 42); + + TMaybe<int> empty; + TMaybe<TestStruct> testStructMaybeEmpty(empty); + UNIT_ASSERT(!testStructMaybeEmpty.Defined()); + } + + Y_UNIT_TEST(TestMaybeCovarianceAssign) { + struct TestStruct { + explicit TestStruct(int value) + : Value_(value) + { + } + TestStruct& operator=(int value) { + Value_ = value; + return *this; + } + int Value_; + }; + + TMaybe<TestStruct> testStructMaybe(Nothing()); + UNIT_ASSERT(!testStructMaybe.Defined()); + + testStructMaybe = TMaybe<int>(42); + UNIT_ASSERT(testStructMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 42); + + testStructMaybe = TMaybe<int>(23); + UNIT_ASSERT(testStructMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 23); + + testStructMaybe = TMaybe<int>(); + UNIT_ASSERT(!testStructMaybe.Defined()); + } + + Y_UNIT_TEST(TestMaybeCovarianceNonTrivial) { + struct TestStruct { + enum { + FromValue, + FromMaybe, + }; + TestStruct(int value) + : Value_(value) + , From_(FromValue) + { + } + TestStruct(TMaybe<int> value) + : Value_(value.Defined() ? value.GetRef() : 0) + , From_(FromMaybe) + { + } + int Value_; + int From_; + }; + + TMaybe<TestStruct> testStructFromMaybe(TMaybe<int>(42)); + UNIT_ASSERT(testStructFromMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructFromMaybe.GetRef().From_, TestStruct::FromMaybe); + UNIT_ASSERT_EQUAL(testStructFromMaybe.GetRef().Value_, 42); + + TMaybe<int> empty; + TMaybe<TestStruct> testStructFromEmptyMaybe(empty); + UNIT_ASSERT(testStructFromEmptyMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructFromEmptyMaybe.GetRef().From_, TestStruct::FromMaybe); + UNIT_ASSERT_EQUAL(testStructFromEmptyMaybe.GetRef().Value_, 0); + + TMaybe<TestStruct> testStructFromValue(23); + UNIT_ASSERT(testStructFromValue.Defined()); + UNIT_ASSERT_EQUAL(testStructFromValue.GetRef().From_, TestStruct::FromValue); + UNIT_ASSERT_EQUAL(testStructFromValue.GetRef().Value_, 23); + } + + Y_UNIT_TEST(TestMaybeCovarianceNonTrivialAssign) { + struct TestStruct { + enum { + FromValue, + FromMaybe, + }; + TestStruct(int value) + : Value_(value) + , From_(FromValue) + { + } + TestStruct(TMaybe<int> value) + : Value_(value.Defined() ? value.GetRef() : 0) + , From_(FromMaybe) + { + } + TestStruct& operator=(int value) { + Value_ = value; + From_ = FromValue; + return *this; + } + TestStruct& operator=(TMaybe<int> value) { + Value_ = value.Defined() ? value.GetRef() : 0; + From_ = FromMaybe; + return *this; + } + int Value_; + int From_; + }; + + TMaybe<TestStruct> testStructMaybe(Nothing()); + testStructMaybe = TMaybe<int>(42); + UNIT_ASSERT(testStructMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().From_, TestStruct::FromMaybe); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 42); + + testStructMaybe = TMaybe<int>(); + UNIT_ASSERT(testStructMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().From_, TestStruct::FromMaybe); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 0); + + testStructMaybe = 23; + UNIT_ASSERT(testStructMaybe.Defined()); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().From_, TestStruct::FromValue); + UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 23); + } + + Y_UNIT_TEST(TestMaybeConvertion) { + struct TSrc {}; + struct TDst { + bool FromMaybeConstructorApplied; + + explicit TDst(TSrc) + : FromMaybeConstructorApplied(false) + { + } + + explicit TDst(TMaybe<TSrc>) + : FromMaybeConstructorApplied(true) + { + } + + TDst& operator=(TSrc) { + FromMaybeConstructorApplied = false; + return *this; + } + TDst& operator=(TMaybe<TSrc>) { + FromMaybeConstructorApplied = true; + return *this; + } + }; + + auto m = TMaybe<TDst>(TMaybe<TSrc>()); + UNIT_ASSERT(m.Defined()); + UNIT_ASSERT(m->FromMaybeConstructorApplied); + + m = TMaybe<TSrc>(); + UNIT_ASSERT(m.Defined()); + UNIT_ASSERT(m->FromMaybeConstructorApplied); + } + + Y_UNIT_TEST(TestOnEmptyException) { + TMaybe<TStringBuf> v; + UNIT_ASSERT_EXCEPTION_CONTAINS(v.GetRef(), yexception, "StringBuf"); + } +} |