blob: cd51d252dd3a0cc180acfc5b1c3bef3821e3399a [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <functional>
#include <gtest/gtest.h>
#include <lib/support/Variant.h>
namespace {
struct Simple
{
bool operator==(const Simple &) const { return true; }
};
struct Pod
{
Pod(int v1, int v2) : m1(v1), m2(v2) {}
bool operator==(const Pod & other) const { return m1 == other.m1 && m2 == other.m2; }
int m1;
int m2;
};
struct Movable
{
Movable(int v1, int v2) : m1(v1), m2(v2) {}
Movable(Movable &) = delete;
Movable & operator=(Movable &) = delete;
Movable(Movable &&) = default;
Movable & operator=(Movable &&) = default;
int m1;
int m2;
};
struct Count
{
Count() { ++created; }
~Count() { ++destroyed; }
Count(const Count &) { ++created; }
Count & operator=(Count &) = default;
Count(Count &&) { ++created; }
Count & operator=(Count &&) = default;
static int created;
static int destroyed;
};
int Count::created = 0;
int Count::destroyed = 0;
using namespace chip;
TEST(TestVariant, TestVariantSimple)
{
Variant<Simple, Pod> v;
EXPECT_FALSE(v.Valid());
v.Set<Pod>(5, 10);
EXPECT_TRUE(v.Valid());
EXPECT_TRUE(v.Is<Pod>());
EXPECT_EQ(v.Get<Pod>().m1, 5);
EXPECT_EQ(v.Get<Pod>().m2, 10);
}
TEST(TestVariant, TestVariantMovable)
{
Variant<Simple, Movable> v;
v.Set<Simple>();
v.Set<Movable>(Movable{ 5, 10 });
EXPECT_EQ(v.Get<Movable>().m1, 5);
EXPECT_EQ(v.Get<Movable>().m2, 10);
auto & m = v.Get<Movable>();
EXPECT_EQ(m.m1, 5);
EXPECT_EQ(m.m2, 10);
v.Set<Simple>();
}
TEST(TestVariant, TestVariantCtorDtor)
{
{
Variant<Simple, Count> v;
EXPECT_EQ(Count::created, 0);
v.Set<Simple>();
EXPECT_EQ(Count::created, 0);
v.Get<Simple>();
EXPECT_EQ(Count::created, 0);
}
{
Variant<Simple, Count> v;
EXPECT_EQ(Count::created, 0);
v.Set<Simple>();
EXPECT_EQ(Count::created, 0);
v.Set<Count>();
EXPECT_EQ(Count::created, 1);
EXPECT_EQ(Count::destroyed, 0);
v.Get<Count>();
EXPECT_EQ(Count::created, 1);
EXPECT_EQ(Count::destroyed, 0);
v.Set<Simple>();
EXPECT_EQ(Count::created, 1);
EXPECT_EQ(Count::destroyed, 1);
v.Set<Count>();
EXPECT_EQ(Count::created, 2);
EXPECT_EQ(Count::destroyed, 1);
}
EXPECT_EQ(Count::destroyed, 2);
{
Variant<Simple, Count> v1;
v1.Set<Count>();
Variant<Simple, Count> v2(v1);
}
EXPECT_EQ(Count::created, 4);
EXPECT_EQ(Count::destroyed, 4);
{
Variant<Simple, Count> v1;
v1.Set<Count>();
Variant<Simple, Count> v2(std::move(v1));
}
EXPECT_EQ(Count::created, 6);
EXPECT_EQ(Count::destroyed, 6);
{
Variant<Simple, Count> v1, v2;
v1.Set<Count>();
v2 = v1;
}
EXPECT_EQ(Count::created, 8);
EXPECT_EQ(Count::destroyed, 8);
{
Variant<Simple, Count> v1, v2;
v1.Set<Count>();
v2 = std::move(v1);
}
EXPECT_EQ(Count::created, 10);
EXPECT_EQ(Count::destroyed, 10);
}
TEST(TestVariant, TestVariantCopy)
{
Variant<Simple, Pod> v1;
v1.Set<Pod>(5, 10);
Variant<Simple, Pod> v2 = v1;
EXPECT_TRUE(v1.Valid());
EXPECT_EQ(v1.Get<Pod>().m1, 5);
EXPECT_EQ(v1.Get<Pod>().m2, 10);
EXPECT_TRUE(v2.Valid());
EXPECT_EQ(v2.Get<Pod>().m1, 5);
EXPECT_EQ(v2.Get<Pod>().m2, 10);
}
TEST(TestVariant, TestVariantMove)
{
Variant<Simple, Movable> v1;
v1.Set<Movable>(5, 10);
Variant<Simple, Movable> v2 = std::move(v1);
EXPECT_FALSE(v1.Valid()); // NOLINT(bugprone-use-after-move)
EXPECT_TRUE(v2.Valid());
EXPECT_EQ(v2.Get<Movable>().m1, 5);
EXPECT_EQ(v2.Get<Movable>().m2, 10);
}
TEST(TestVariant, TestVariantCopyAssign)
{
Variant<Simple, Pod> v1;
Variant<Simple, Pod> v2;
v1.Set<Pod>(5, 10);
v2 = v1;
EXPECT_TRUE(v1.Valid());
EXPECT_EQ(v1.Get<Pod>().m1, 5);
EXPECT_EQ(v1.Get<Pod>().m2, 10);
EXPECT_TRUE(v2.Valid());
EXPECT_EQ(v2.Get<Pod>().m1, 5);
EXPECT_EQ(v2.Get<Pod>().m2, 10);
}
TEST(TestVariant, TestVariantMoveAssign)
{
Variant<Simple, Pod> v1;
Variant<Simple, Pod> v2;
v1.Set<Pod>(5, 10);
v2 = std::move(v1);
EXPECT_FALSE(v1.Valid()); // NOLINT(bugprone-use-after-move)
EXPECT_TRUE(v2.Valid());
EXPECT_EQ(v2.Get<Pod>().m1, 5);
EXPECT_EQ(v2.Get<Pod>().m2, 10);
}
TEST(TestVariant, TestVariantInPlace)
{
int i = 0;
Variant<std::reference_wrapper<int>> v1 = Variant<std::reference_wrapper<int>>(InPlaceTemplate<std::reference_wrapper<int>>, i);
EXPECT_TRUE(v1.Valid());
EXPECT_TRUE(v1.Is<std::reference_wrapper<int>>());
EXPECT_EQ(&v1.Get<std::reference_wrapper<int>>().get(), &i);
Variant<std::reference_wrapper<int>> v2 = Variant<std::reference_wrapper<int>>::Create<std::reference_wrapper<int>>(i);
EXPECT_TRUE(v2.Valid());
EXPECT_TRUE(v2.Is<std::reference_wrapper<int>>());
EXPECT_EQ(&v2.Get<std::reference_wrapper<int>>().get(), &i);
}
TEST(TestVariant, TestVariantCompare)
{
Variant<Simple, Pod> v0;
Variant<Simple, Pod> v1;
Variant<Simple, Pod> v2;
Variant<Simple, Pod> v3;
Variant<Simple, Pod> v4;
v1.Set<Simple>();
v2.Set<Pod>(5, 10);
v3.Set<Pod>(5, 10);
v4.Set<Pod>(5, 11);
EXPECT_TRUE(v0 == v0);
EXPECT_FALSE(v0 == v1);
EXPECT_FALSE(v0 == v2);
EXPECT_FALSE(v0 == v3);
EXPECT_FALSE(v0 == v4);
EXPECT_FALSE(v1 == v0);
EXPECT_TRUE(v1 == v1);
EXPECT_FALSE(v1 == v2);
EXPECT_FALSE(v1 == v3);
EXPECT_FALSE(v1 == v4);
EXPECT_FALSE(v2 == v0);
EXPECT_FALSE(v2 == v1);
EXPECT_TRUE(v2 == v2);
EXPECT_TRUE(v2 == v3);
EXPECT_FALSE(v2 == v4);
EXPECT_FALSE(v3 == v0);
EXPECT_FALSE(v3 == v1);
EXPECT_TRUE(v3 == v2);
EXPECT_TRUE(v3 == v3);
EXPECT_FALSE(v3 == v4);
EXPECT_FALSE(v4 == v0);
EXPECT_FALSE(v4 == v1);
EXPECT_FALSE(v4 == v2);
EXPECT_FALSE(v4 == v3);
EXPECT_TRUE(v4 == v4);
}
} // namespace