#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");
}
}