aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/maybe_ut.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/maybe_ut.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/maybe_ut.cpp')
-rw-r--r--util/generic/maybe_ut.cpp1006
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");
+ }
+}