#include #include #include #include #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; static_assert(std::is_trivially_copy_constructible::value, ""); static_assert(std::is_trivially_destructible::value, ""); using T2 = TMaybe; static_assert(std::is_trivially_copy_constructible::value, ""); static_assert(std::is_trivially_destructible::value, ""); using T3 = TMaybe>; static_assert(std::is_trivially_copy_constructible::value, ""); static_assert(std::is_trivially_destructible::value, ""); using T4 = TMaybe; static_assert(!std::is_trivially_copy_constructible::value, ""); static_assert(!std::is_trivially_destructible::value, ""); } Y_UNIT_TEST(TestWarning) { TMaybe 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(); UNIT_ASSERT_VALUES_EQUAL(a, b); TMaybe(TIncrementOnDestroy(&a)); b += 2; UNIT_ASSERT_VALUES_EQUAL(a, b); { TMaybe m1 = TIncrementOnDestroy(&a); b += 1; UNIT_ASSERT_VALUES_EQUAL(a, b); TMaybe m2 = m1; UNIT_ASSERT_VALUES_EQUAL(a, b); TMaybe m3; m3 = m1; UNIT_ASSERT_VALUES_EQUAL(a, b); } b += 3; UNIT_ASSERT_VALUES_EQUAL(a, b); { TMaybe 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 m5; UNIT_ASSERT(!m5.Defined()); UNIT_ASSERT(m5.Empty()); UNIT_ASSERT(m5 == TMaybe()); UNIT_ASSERT(m5 == Nothing()); UNIT_ASSERT(m5 != TMaybe(4)); m5 = 4; UNIT_ASSERT(m5.Defined()); UNIT_ASSERT(!m5.Empty()); UNIT_ASSERT_VALUES_EQUAL(4, m5.GetRef()); UNIT_ASSERT(m5 == TMaybe(4)); UNIT_ASSERT(m5 != TMaybe(3)); UNIT_ASSERT(m5 != TMaybe()); UNIT_ASSERT(m5 != Nothing()); m5 = TMaybe(5); UNIT_ASSERT(m5.Defined()); UNIT_ASSERT_VALUES_EQUAL(5, m5.GetRef()); UNIT_ASSERT(m5 == TMaybe(5)); UNIT_ASSERT(m5 != TMaybe(4)); m5 = TMaybe(); UNIT_ASSERT(m5.Empty()); UNIT_ASSERT(m5 == TMaybe()); UNIT_ASSERT(m5 == Nothing()); UNIT_ASSERT(m5 != TMaybe(5)); m5 = 4; m5 = Nothing(); UNIT_ASSERT(m5.Empty()); UNIT_ASSERT(m5 == TMaybe()); UNIT_ASSERT(m5 == Nothing()); UNIT_ASSERT(m5 != TMaybe(5)); m5 = {}; UNIT_ASSERT(m5.Empty()); } Y_UNIT_TEST(TestInPlace) { TMaybe 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 m1(std::move(value1)); UNIT_ASSERT(m1.Defined()); UNIT_ASSERT_VALUES_EQUAL(m1->Flag, 1); // Move assignment from value TMovable value2(2); TMaybe m2; m2 = std::move(value2); UNIT_ASSERT(m2.Defined()); UNIT_ASSERT_VALUES_EQUAL(m2->Flag, 2); // Move ctor from maybe TMaybe m3(std::move(m1)); UNIT_ASSERT(m3.Defined()); UNIT_ASSERT_VALUES_EQUAL(m3->Flag, 1); // Move assignment from maybe TMaybe 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(5); UNIT_ASSERT_VALUES_EQUAL(o5.Flag, 5); TMovable o6 = MakeMaybe(6).GetRef(); UNIT_ASSERT_VALUES_EQUAL(o6.Flag, 6); } Y_UNIT_TEST(TestCast) { // Undefined maybe casts to undefined maybe TMaybe shortMaybe; const auto undefinedMaybe = shortMaybe.Cast(); UNIT_ASSERT(!undefinedMaybe.Defined()); // Defined maybe casts to defined maybe of another type shortMaybe = 34; const auto longMaybe = shortMaybe.Cast(); UNIT_ASSERT(longMaybe.Defined()); UNIT_ASSERT_VALUES_EQUAL(34, longMaybe.GetRef()); } Y_UNIT_TEST(TestGetOr) { UNIT_ASSERT_VALUES_EQUAL(TMaybe().GetOrElse("xxx"), TString("xxx")); UNIT_ASSERT_VALUES_EQUAL(TMaybe("yyy").GetOrElse("xxx"), TString("yyy")); { TString xxx = "xxx"; UNIT_ASSERT_VALUES_EQUAL(TMaybe().GetOrElse(xxx).append('x'), TString("xxxx")); UNIT_ASSERT_VALUES_EQUAL(xxx, "xxxx"); } { TString xxx = "xxx"; UNIT_ASSERT_VALUES_EQUAL(TMaybe("yyy").GetOrElse(xxx).append('x'), TString("yyyx")); UNIT_ASSERT_VALUES_EQUAL(xxx, "xxx"); } } /* == != < <= > >= */ Y_UNIT_TEST(TestCompareEqualEmpty) { TMaybe m1; TMaybe 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 m1{1}; TMaybe 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 m1{1}; TMaybe 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 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 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 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 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 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 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 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 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 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 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(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(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>({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(1, 2, 3); UNIT_ASSERT(m4->A_ == 1); UNIT_ASSERT(m4->B_ == 2); UNIT_ASSERT(m4->C_ == 3); } { struct TMockStruct5 { TMockStruct5(const TVector& vec, bool someFlag) : Vec_(vec) , SomeFlag_(someFlag) { } TVector Vec_; bool SomeFlag_; }; auto m5 = MakeMaybe({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 m1 = 1; TMaybe m2 = 2; UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(*m2 == 2); m1.Swap(m2); UNIT_ASSERT(*m1 == 2); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = 1; TMaybe m2 = Nothing(); UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(m2 == Nothing()); m1.Swap(m2); UNIT_ASSERT(m1 == Nothing()); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = Nothing(); TMaybe 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 m1 = 1; TMaybe m2 = 2; UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(*m2 == 2); m1.swap(m2); UNIT_ASSERT(*m1 == 2); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = 1; TMaybe m2 = Nothing(); UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(m2 == Nothing()); m1.swap(m2); UNIT_ASSERT(m1 == Nothing()); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = Nothing(); TMaybe 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 m1 = 1; TMaybe m2 = 2; UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(*m2 == 2); ::Swap(m1, m2); UNIT_ASSERT(*m1 == 2); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = 1; TMaybe m2 = Nothing(); UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(m2 == Nothing()); ::Swap(m1, m2); UNIT_ASSERT(m1 == Nothing()); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = Nothing(); TMaybe 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 m1 = 1; TMaybe m2 = 2; UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(*m2 == 2); ::DoSwap(m1, m2); UNIT_ASSERT(*m1 == 2); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = 1; TMaybe m2 = Nothing(); UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(m2 == Nothing()); ::DoSwap(m1, m2); UNIT_ASSERT(m1 == Nothing()); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = Nothing(); TMaybe 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 m1 = 1; TMaybe m2 = 2; UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(*m2 == 2); ::std::swap(m1, m2); UNIT_ASSERT(*m1 == 2); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = 1; TMaybe m2 = Nothing(); UNIT_ASSERT(*m1 == 1); UNIT_ASSERT(m2 == Nothing()); ::std::swap(m1, m2); UNIT_ASSERT(m1 == Nothing()); UNIT_ASSERT(*m2 == 1); } { TMaybe m1 = Nothing(); TMaybe 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(); 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(42); UNIT_ASSERT_EQUAL("42", s); } Y_UNIT_TEST(TestMaybeCovarianceImplicit) { struct TestStruct { TestStruct(int value) : Value_(value) { } operator int() const { return Value_; } static TMaybe Unwrap(TMaybe testStructMaybe) { return testStructMaybe; } int Value_; }; TMaybe testMaybeFull = TestStruct::Unwrap(TMaybe(42)); UNIT_ASSERT(testMaybeFull.Defined()); UNIT_ASSERT_EQUAL(testMaybeFull.GetRef(), 42); TMaybe testMaybeEmpty = TestStruct::Unwrap(TMaybe()); UNIT_ASSERT(!testMaybeEmpty.Defined()); } Y_UNIT_TEST(TestMaybeCovarianceExplicit) { struct TestStruct { explicit TestStruct(int value) : Value_(value) { } int Value_; }; TMaybe testStructMaybeFull(TMaybe(42)); UNIT_ASSERT(testStructMaybeFull.Defined()); UNIT_ASSERT_EQUAL(testStructMaybeFull.GetRef().Value_, 42); TMaybe empty; TMaybe 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 testStructMaybe(Nothing()); UNIT_ASSERT(!testStructMaybe.Defined()); testStructMaybe = TMaybe(42); UNIT_ASSERT(testStructMaybe.Defined()); UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 42); testStructMaybe = TMaybe(23); UNIT_ASSERT(testStructMaybe.Defined()); UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 23); testStructMaybe = TMaybe(); UNIT_ASSERT(!testStructMaybe.Defined()); } Y_UNIT_TEST(TestMaybeCovarianceNonTrivial) { struct TestStruct { enum { FromValue, FromMaybe, }; TestStruct(int value) : Value_(value) , From_(FromValue) { } TestStruct(TMaybe value) : Value_(value.Defined() ? value.GetRef() : 0) , From_(FromMaybe) { } int Value_; int From_; }; TMaybe testStructFromMaybe(TMaybe(42)); UNIT_ASSERT(testStructFromMaybe.Defined()); UNIT_ASSERT_EQUAL(testStructFromMaybe.GetRef().From_, TestStruct::FromMaybe); UNIT_ASSERT_EQUAL(testStructFromMaybe.GetRef().Value_, 42); TMaybe empty; TMaybe testStructFromEmptyMaybe(empty); UNIT_ASSERT(testStructFromEmptyMaybe.Defined()); UNIT_ASSERT_EQUAL(testStructFromEmptyMaybe.GetRef().From_, TestStruct::FromMaybe); UNIT_ASSERT_EQUAL(testStructFromEmptyMaybe.GetRef().Value_, 0); TMaybe 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 value) : Value_(value.Defined() ? value.GetRef() : 0) , From_(FromMaybe) { } TestStruct& operator=(int value) { Value_ = value; From_ = FromValue; return *this; } TestStruct& operator=(TMaybe value) { Value_ = value.Defined() ? value.GetRef() : 0; From_ = FromMaybe; return *this; } int Value_; int From_; }; TMaybe testStructMaybe(Nothing()); testStructMaybe = TMaybe(42); UNIT_ASSERT(testStructMaybe.Defined()); UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().From_, TestStruct::FromMaybe); UNIT_ASSERT_EQUAL(testStructMaybe.GetRef().Value_, 42); testStructMaybe = TMaybe(); 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) : FromMaybeConstructorApplied(true) { } TDst& operator=(TSrc) { FromMaybeConstructorApplied = false; return *this; } TDst& operator=(TMaybe) { FromMaybeConstructorApplied = true; return *this; } }; auto m = TMaybe(TMaybe()); UNIT_ASSERT(m.Defined()); UNIT_ASSERT(m->FromMaybeConstructorApplied); m = TMaybe(); UNIT_ASSERT(m.Defined()); UNIT_ASSERT(m->FromMaybeConstructorApplied); } Y_UNIT_TEST(TestOnEmptyException) { TMaybe v; UNIT_ASSERT_EXCEPTION_CONTAINS(v.GetRef(), yexception, "StringBuf"); } }