From e59cf7b09e7388d369e8d2bf73501cde79c28708 Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Thu, 8 Apr 2021 16:43:58 +0200 Subject: Squashed 'EASTL/' content from commit fad5471 git-subtree-dir: EASTL git-subtree-split: fad54717f8e4ebb13b20095da7efd07a53af0f10 --- test/source/TestVariant.cpp | 890 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 890 insertions(+) create mode 100644 test/source/TestVariant.cpp (limited to 'test/source/TestVariant.cpp') diff --git a/test/source/TestVariant.cpp b/test/source/TestVariant.cpp new file mode 100644 index 0000000..8c71eda --- /dev/null +++ b/test/source/TestVariant.cpp @@ -0,0 +1,890 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" +#include +#include +#include + +#ifdef EA_COMPILER_CPP14_ENABLED +#include "ConceptImpls.h" +#include + + +int TestVariantAlternative() +{ + using namespace eastl; + int nErrorCount = 0; + { + using v_t = variant; + static_assert(is_same_v, int>, "error variant_alternative"); + } + { + using v_t = variant; + + static_assert(is_same_v, int>, "error variant_alternative"); + static_assert(is_same_v, long>, "error variant_alternative"); + static_assert(is_same_v, short>, "error variant_alternative"); + static_assert(is_same_v, char>, "error variant_alternative"); + } + { + struct custom_type1 {}; + struct custom_type2 {}; + struct custom_type3 {}; + + using v_t = variant; + + static_assert(is_same_v, unsigned>, "error variant_alternative"); + static_assert(is_same_v, signed>, "error variant_alternative"); + static_assert(is_same_v, custom_type1>, "error variant_alternative"); + static_assert(is_same_v, custom_type2>, "error variant_alternative"); + static_assert(is_same_v, custom_type3>, "error variant_alternative"); + } + // cv-qualifier tests + { + using v_t = variant; + + static_assert(is_same_v, int>, "error variant_alternative"); + static_assert(is_same_v, const int>, "error variant_alternative"); + static_assert(is_same_v, volatile int>, "error variant_alternative"); + static_assert(is_same_v, const volatile int>, "error variant_alternative"); + } + return nErrorCount; +} + +int TestVariantSize() +{ + using namespace eastl; + int nErrorCount = 0; + + static_assert(variant_size>() == 1, "error variant_size"); + static_assert(variant_size>() == 2, "error variant_size"); + static_assert(variant_size>() == 4, "error variant_size"); + static_assert(variant_size>() == 1, "error variant_size"); + static_assert(variant_size>() == 1, "error variant_size"); + static_assert(variant_size>() == 1, "error variant_size"); + + static_assert(variant_size_v> == 1, "error variant_size"); + static_assert(variant_size_v> == 2, "error variant_size"); + static_assert(variant_size_v> == 4, "error variant_size"); + static_assert(variant_size_v> == 1, "error variant_size"); + static_assert(variant_size_v> == 1, "error variant_size"); + static_assert(variant_size_v> == 1, "error variant_size"); + + static_assert(variant_size_v> == 2, "error variant_size_v"); + static_assert(variant_size_v> == 2, "error variant_size_v"); + static_assert(variant_size_v> == 3, "error variant_size_v"); + + return nErrorCount; +} + +int TestVariantHash() +{ + using namespace eastl; + int nErrorCount = 0; + + { hash h; EA_UNUSED(h); } + + return nErrorCount; +} + +int TestVariantBasic() +{ + using namespace eastl; + int nErrorCount = 0; + + { VERIFY(variant_npos == size_t(-1)); } + + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + + { + struct MyObj + { + MyObj() : i(1337) {} + ~MyObj() {} + + int i; + }; + + struct MyObj2 + { + MyObj2(int& ii) : i(ii) {} + ~MyObj2() {} + + MyObj2& operator=(const MyObj2&) = delete; + + int& i; + }; + + static_assert(!eastl::is_trivially_destructible_v, "MyObj can't be trivially destructible"); + static_assert(!eastl::is_trivially_destructible_v, "MyObj2 can't be trivially destructible"); + + { + eastl::variant myVar; + VERIFY(get(myVar).i == 1337); + } + + { + eastl::variant myVar = MyObj(); + VERIFY(get(myVar).i == 1337); + } + + { + int i = 42; + eastl::variant myVar = MyObj2(i); + VERIFY(get(myVar).i == 42); + } + + { + auto m = MyObj(); + m.i = 2000; + + eastl::variant myVar = m; + VERIFY(get(myVar).i == 2000); + } + } + + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + { variant v; EA_UNUSED(v); } + + { + // verify constructors and destructors are called + { + variant v = TestObject(1337); + VERIFY((get(v)).mX == 1337); + + variant vCopy = v; + VERIFY((get(vCopy)).mX == 1337); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + + { + variant v; + VERIFY(*(get_if(&v)) == ""); + VERIFY(get_if(&v)->empty()); + VERIFY(get_if(&v)->length() == 0); + VERIFY(get_if(&v)->size() == 0); + + *(get_if(&v)) += 'a'; + VERIFY(*(get_if(&v)) == "a"); + } + + return nErrorCount; +} + +int TestVariantGet() +{ + using namespace eastl; + int nErrorCount = 0; + + { + const char* strValue = "canada"; + using v_t = variant; + { + v_t v; + v = 42; + VERIFY(v.index() == 0); + VERIFY(*get_if(&v) == 42); + VERIFY(get(v) == 42); + VERIFY( holds_alternative(v)); + VERIFY(!holds_alternative(v)); + } + { + v_t v; + v = strValue; + VERIFY(v.index() == 1); + VERIFY(*get_if(&v) == strValue); + VERIFY(get(v) == strValue); + VERIFY(!holds_alternative(v)); + VERIFY(holds_alternative(v)); + VERIFY(get(move(v)) == strValue); + } + { + v_t v; + v = 42; + VERIFY(v.index() == 0); + VERIFY(*get_if<0>(&v) == 42); + VERIFY(get<0>(v) == 42); + VERIFY( holds_alternative(v)); + VERIFY(!holds_alternative(v)); + } + { + v_t v; + v = strValue; + VERIFY(v.index() == 1); + VERIFY(*get_if<1>(&v) == strValue); + VERIFY(get<1>(v) == strValue); + VERIFY(!holds_alternative(v)); + VERIFY( holds_alternative(v)); + } + { + v_t v; + v = strValue; + VERIFY(v.index() == 1); + VERIFY(*get_if<1>(&v) == strValue); + VERIFY(get_if<0>(&v) == nullptr); + } + { + VERIFY(get_if<0>((v_t*)nullptr) == nullptr); + VERIFY(get_if<1>((v_t*)nullptr) == nullptr); + } + } + + return nErrorCount; +} + +int TestVariantHoldsAlternative() +{ + using namespace eastl; + int nErrorCount = 0; + + { + { + using v_t = variant; // default construct first type + v_t v; + + VERIFY(!holds_alternative(v)); // Verify that a query for a T not in the variant typelist returns false. + VERIFY(!holds_alternative(v)); // Verify that a query for a T not in the variant typelist returns false. + VERIFY( holds_alternative(v)); // variant does hold an int, because its a default constructible first parameter + VERIFY(!holds_alternative(v)); // variant does not hold a short + } + + { + using v_t = variant; // default construct monostate + v_t v; + + VERIFY(!holds_alternative(v)); // Verify that a query for a T not in the variant typelist returns false. + VERIFY(!holds_alternative(v)); // Verify that a query for a T not in the variant typelist returns false. + VERIFY(!holds_alternative(v)); // variant does not hold an int + VERIFY(!holds_alternative(v)); // variant does not hold a short + } + + { + using v_t = variant; + + { + v_t v; + VERIFY(!holds_alternative(v)); // variant does not hold an int + + v = 42; + VERIFY(holds_alternative(v)); // variant does hold an int + } + + { + v_t v1, v2; + VERIFY(!holds_alternative(v1)); + VERIFY(!holds_alternative(v2)); + + v1 = 42; + VERIFY(holds_alternative(v1)); + VERIFY(!holds_alternative(v2)); + + eastl::swap(v1, v2); + VERIFY(!holds_alternative(v1)); + VERIFY(holds_alternative(v2)); + } + } + } + + return nErrorCount; +} + +int TestVariantValuelessByException() +{ + using namespace eastl; + int nErrorCount = 0; + + { + { + using v_t = variant; + static_assert(eastl::is_default_constructible_v, "valueless_by_exception error"); + + v_t v; + VERIFY(!v.valueless_by_exception()); + + v = 42; + VERIFY(!v.valueless_by_exception()); + } + + { + using v_t = variant; + static_assert(eastl::is_default_constructible_v, "valueless_by_exception error"); + + v_t v1, v2; + VERIFY(!v1.valueless_by_exception()); + VERIFY(!v2.valueless_by_exception()); + + v1 = 42; + VERIFY(!v1.valueless_by_exception()); + VERIFY(!v2.valueless_by_exception()); + + eastl::swap(v1, v2); + VERIFY(!v1.valueless_by_exception()); + VERIFY(!v2.valueless_by_exception()); + + v1 = v2; + VERIFY(!v1.valueless_by_exception()); + VERIFY(!v2.valueless_by_exception()); + } + + { + struct NotDefaultConstructibleButHasConversionCtor + { + NotDefaultConstructibleButHasConversionCtor() = delete; + NotDefaultConstructibleButHasConversionCtor(int) {} + }; + static_assert(!eastl::is_default_constructible::value, "valueless_by_exception error"); + + using v_t = variant; + v_t v(42); + static_assert(!eastl::is_default_constructible_v, "valueless_by_exception error"); + VERIFY(!v.valueless_by_exception()); + } + + // TODO(rparolin): review exception safety for variant types + // + // { + // #if EASTL_EXCEPTIONS_ENABLED + // struct DefaultConstructibleButThrows + // { + // DefaultConstructibleButThrows() {} + // ~DefaultConstructibleButThrows() {} + // + // DefaultConstructibleButThrows(DefaultConstructibleButThrows&&) { throw 42; } + // DefaultConstructibleButThrows(const DefaultConstructibleButThrows&) { throw 42; } + // DefaultConstructibleButThrows& operator=(const DefaultConstructibleButThrows&) { throw 42; } + // DefaultConstructibleButThrows& operator=(DefaultConstructibleButThrows&&) { throw 42; } + // }; + // + // using v_t = variant; + // + // v_t v1; + // VERIFY(!v1.valueless_by_exception()); + // + // try + // { + // v1 = DefaultConstructibleButThrows(); + // } + // catch (...) + // { + // VERIFY(v1.valueless_by_exception()); + // } + // #endif + // } + } + + return nErrorCount; +} + +int TestVariantCopyAndMove() +{ + using namespace eastl; + int nErrorCount = 0; + + { + { + using v_t = variant; + + v_t v1 = 42; + v_t v2 = v1; + + VERIFY(get(v2) == get(v1)); + } + + } + + return nErrorCount; +} + +int TestVariantEmplace() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v; + v.emplace(42); + VERIFY(get(v) == 42); + } + { + variant v; + v.emplace<0>(42); + VERIFY(get<0>(v) == 42); + } + + { + variant v; + + v.emplace<0>(42); + VERIFY(get<0>(v) == 42); + + v.emplace<1>(short(43)); + VERIFY(get<1>(v) == short(43)); + + v.emplace<2>(44L); + VERIFY(get<2>(v) == 44L); + } + { + variant v; + + v.emplace(42); + VERIFY(get(v) == 42); + + v.emplace(short(43)); + VERIFY(get(v) == short(43)); + + v.emplace(44L); + VERIFY(get(v) == 44L); + } + + { + { + variant v; + v.emplace<0>(1337); + VERIFY(get<0>(v).mX == 1337); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + + { + { + variant v; + + v.emplace(42); + VERIFY(get(v) == 42); + + v.emplace(1337); + VERIFY(get(v).mX == 1337); + + v.emplace(1338, 42, 3); + VERIFY(get(v).mX == 1338 + 42 + 3); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + + { + { + struct r { + r() = default; + r(int x) : mX(x) {} + int mX; + }; + + variant v; + + v.emplace<0>(42); + VERIFY(get<0>(v) == 42); + + v.emplace<1>(1337); + VERIFY(get<1>(v).mX == 1337); + } + } + + { + struct r { + r() = default; + r(int a, int b, int c, int d) : a(a), b(b), c(c), d(d) {} + r(std::initializer_list l) + { + auto it = l.begin(); + + a = *it++; + b = *it++; + c = *it++; + d = *it++; + } + int a, b, c, d; + }; + + r aa{1,2,3,4}; + VERIFY(aa.a == 1); + VERIFY(aa.b == 2); + VERIFY(aa.c == 3); + VERIFY(aa.d == 4); + + variant v; + v.emplace<0>(std::initializer_list{1,2,3,4}); + + VERIFY(get(v).a == 1); + VERIFY(get(v).b == 2); + VERIFY(get(v).c == 3); + VERIFY(get(v).d == 4); + } + + return nErrorCount; +} + +int TestVariantSwap() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v1 = 42; + variant v2 = 24; + + v1.swap(v2); + + VERIFY(get(v1) == 24); + VERIFY(get(v2) == 42); + + v1.swap(v2); + + VERIFY(get(v1) == 42); + VERIFY(get(v2) == 24); + } + + { + variant v1 = "Hello"; + variant v2 = "World"; + + VERIFY(get(v1) == "Hello"); + VERIFY(get(v2) == "World"); + + v1.swap(v2); + + VERIFY(get(v1) == "World"); + VERIFY(get(v2) == "Hello"); + } + + return nErrorCount; +} + +int TestVariantRelOps() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v1 = 42; + variant v2 = 24; + variant v1e = v1; + + VERIFY(v1 == v1e); + VERIFY(v1 != v2); + VERIFY(v1 > v2); + VERIFY(v2 < v1); + } + + { + vector> v = {{1}, {3}, {7}, {4}, {0}, {5}, {2}, {6}, {8}}; + eastl::sort(v.begin(), v.end()); + VERIFY(eastl::is_sorted(v.begin(), v.end())); + } + + return nErrorCount; +} + + +int TestVariantInplaceCtors() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v(in_place<0>, 42); + VERIFY(get<0>(v) == 42); + VERIFY(v.index() == 0); + } + + { + variant v(in_place<1>, 42); + VERIFY(get<1>(v) == 42); + VERIFY(v.index() == 1); + } + + { + variant v(in_place, 42); + VERIFY(get<0>(v) == 42); + VERIFY(v.index() == 0); + } + + { + variant v(in_place, "hello"); + VERIFY(get<1>(v) == "hello"); + VERIFY(v.index() == 1); + } + + return nErrorCount; +} + + +int TestVariantVisitor() +{ + using namespace eastl; + int nErrorCount = 0; + + using v_t = variant; + + // TODO(rparolin): When we have a C++17 compiler + // + // template deduction guides test + // template struct overloaded : Ts... { using Ts::operator()...; }; + // template overloaded(Ts...) -> overloaded; + + // { + // v_t arr[] = {42, "rob", 42.0, 42L}; + + // int count = 0; + // for (auto& e : arr) + // { + // eastl::visit(overloaded{[&](int) { count++; }, + // [&](string) { count++; }, + // [&](double) { count++; }, + // [&](long) { count++; }}, e); + // } + // } + + { + v_t arr[] = {42, "hello", 42.0, 42L}; + + int count = 0; + for (auto& e : arr) + { + eastl::visit([&](auto){ count++; }, e); + } + + VERIFY(count == EAArrayCount(arr)); + } + + { + static bool bVisited = false; + + variant v = 42; + + struct MyVisitor + { + MyVisitor& operator()(int) { bVisited = true; return *this; }; + MyVisitor& operator()(long) { return *this; }; + MyVisitor& operator()(string) { return *this; }; + MyVisitor& operator()(unsigned) { return *this; }; // not in variant + }; + + visit(MyVisitor{}, v); + VERIFY(bVisited); + } + + { + static bool bVisited = false; + + variant i = 42; + variant s = "hello"; + + struct MultipleVisitor + { + MultipleVisitor& operator()(int, int) { return *this; } + MultipleVisitor& operator()(int, string) { bVisited = true; return *this; } + MultipleVisitor& operator()(string, int) { return *this; } + MultipleVisitor& operator()(string, string) { return *this; } + }; + + visit(MultipleVisitor{}, i, s); + VERIFY(bVisited); + } + + { + variant v = 42; + + struct ModifyingVisitor + { + void operator()(int &i) { i += 1; } + void operator()(string &s) { s += "hello"; } + }; + + visit(ModifyingVisitor{}, v); + VERIFY(get<0>(v) == 43); + } + + { + variant v = 42; + + struct ReturningVisitor + { + int operator()(int i) {return i;} + int operator()(string s) {return 0;} + }; + + VERIFY(visit(ReturningVisitor{}, v) == 42); + } + +#if !defined(EA_COMPILER_MSVC) + { + variant v = 42; + + struct ReturningDifferentTypesVisitor + { + int operator()(int i) {return i;} + size_t operator()(string s) {return s.size();} + }; + + VERIFY(visit(ReturningDifferentTypesVisitor{}, v) == 42); + } +#endif + + return nErrorCount; +} + + +int TestVariantAssignment() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v = TestObject(1337); + VERIFY(get(v).mX == 1337); + TestObject::Reset(); + + v.operator=(42); // ensure assignment-operator is called + VERIFY(TestObject::sTODtorCount == 1); // verify TestObject dtor is called. + VERIFY(get(v) == 42); + TestObject::Reset(); + } + + return nErrorCount; +} + + +int TestVariantMoveOnly() +{ + using namespace eastl; + int nErrorCount = 0; + + { + variant v = MoveOnlyType(1337); + VERIFY(get(v).mVal == 1337); + } + + return nErrorCount; +} + + +//compilation test related to PR #315: converting constructor and assignment operator compilation error +void TestCompilation(const double e) { eastl::variant v{e}; } + + + +int TestVariantUserRegressionCopyMoveAssignmentOperatorLeak() +{ + using namespace eastl; + int nErrorCount = 0; + + { + { + eastl::variant v = TestObject(1337); + VERIFY(eastl::get(v).mX == 1337); + eastl::variant v2 = TestObject(1338); + VERIFY(eastl::get(v2).mX == 1338); + v.operator=(v2); + VERIFY(eastl::get(v).mX == 1338); + VERIFY(eastl::get(v2).mX == 1338); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + { + { + eastl::variant v = TestObject(1337); + VERIFY(eastl::get(v).mX == 1337); + eastl::variant v2 = TestObject(1338); + VERIFY(eastl::get(v2).mX == 1338); + v.operator=(eastl::move(v2)); + VERIFY(eastl::get(v).mX == 1338); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + { + { + eastl::variant v = TestObject(1337); + VERIFY(eastl::get(v).mX == 1337); + v = {}; + VERIFY(eastl::get(v).mX == 0); + } + VERIFY(TestObject::IsClear()); + TestObject::Reset(); + } + + return nErrorCount; +} + + +int TestVariantUserRegressionIncompleteType() +{ + using namespace eastl; + int nErrorCount = 0; + + { + struct B; + + struct A + { + vector> v; + }; + + struct B + { + vector> v; + }; + } + + return nErrorCount; +} + +int TestVariantGeneratingComparisonOverloads(); + +int TestVariant() +{ + int nErrorCount = 0; + + nErrorCount += TestVariantBasic(); + nErrorCount += TestVariantSize(); + nErrorCount += TestVariantAlternative(); + nErrorCount += TestVariantValuelessByException(); + nErrorCount += TestVariantGet(); + nErrorCount += TestVariantHoldsAlternative(); + nErrorCount += TestVariantHash(); + nErrorCount += TestVariantCopyAndMove(); + nErrorCount += TestVariantSwap(); + nErrorCount += TestVariantEmplace(); + nErrorCount += TestVariantRelOps(); + nErrorCount += TestVariantInplaceCtors(); + nErrorCount += TestVariantVisitor(); + nErrorCount += TestVariantAssignment(); + nErrorCount += TestVariantMoveOnly(); + nErrorCount += TestVariantUserRegressionCopyMoveAssignmentOperatorLeak(); + nErrorCount += TestVariantUserRegressionIncompleteType(); + nErrorCount += TestVariantGeneratingComparisonOverloads(); + + return nErrorCount; +} +#else + int TestVariant() { return 0; } +#endif + + + + + + + + + + -- cgit v1.2.3