Skip to content

Commit

Permalink
Fixed unit-tests with new AsEnum implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Alkenso committed Aug 2, 2019
1 parent cfe9056 commit 71f6f6b
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 102 deletions.
43 changes: 19 additions & 24 deletions include/asenum/asenum.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ namespace asenum
@param value Value related to specified enum case.
@return AsEnum instance holding value of specified case.
*/
template <Enum Case, typename T = typename std::enable_if<!std::is_same<UnderlyingType<Case>, void>::value>::type>
static AsEnum create(T value);
template <Enum Case, typename U = typename std::enable_if<!std::is_same<UnderlyingType<Case>, void>::value>::type>
static AsEnum create(UnderlyingType<Case> value) { return createImpl<Case, UnderlyingType<Case>>(std::move(value)); }

/**
Creates AsEnum instance of specific case with 'void' associated type.
Expand All @@ -103,7 +103,7 @@ namespace asenum
template <Enum Case>
bool isCase() const;

#error add example
//#error add example
/**
Unwraps AsEnum and provides access to value that it holds.
Expand All @@ -114,18 +114,18 @@ namespace asenum
template <Enum Case, typename Handler>
bool ifCase(const Handler& handler) const;

#error add example
//#error add example
/**
Performs switch-like action allowing to wotk with values of different cases.
*/
details::AsSwitch<Enum, AsEnum<T_Cases...>> doSwitch() const;

private:
template <typename T, typename RealT = typename std::remove_reference<T>::type>
AsEnum(const Enum relatedCase, T&& value);
AsEnum(const Enum relatedCase, std::shared_ptr<void> value);

explicit AsEnum(const Enum relatedCase);
template <Enum Case, typename T>
static AsEnum createImpl(T&& value);

template <typename T, typename Handler>
static typename std::enable_if<std::is_same<T, void>::value, void>::type call(const void*, const Handler& handler);
Expand Down Expand Up @@ -219,16 +219,23 @@ constexpr typename asenum::AsEnum<T_Cases...>::Enum asenum::AsEnum<T_Cases...>::

template <typename... T_Cases>
template <typename asenum::AsEnum<T_Cases...>::Enum Case, typename T>
asenum::AsEnum<T_Cases...> asenum::AsEnum<T_Cases...>::create(T value)
asenum::AsEnum<T_Cases...> asenum::AsEnum<T_Cases...>::createImpl(T&& value)
{
return asenum::AsEnum<T_Cases...>(Case, value);
std::shared_ptr<void> internalValue(new T(std::forward<T>(value)), [] (void* ptr) {
if (ptr)
{
delete reinterpret_cast<T*>(ptr);
}
});

return asenum::AsEnum<T_Cases...>(Case, internalValue);
}

template <typename... T_Cases>
template <typename asenum::AsEnum<T_Cases...>::Enum Case, typename T>
asenum::AsEnum<T_Cases...> asenum::AsEnum<T_Cases...>::create()
{
return asenum::AsEnum<T_Cases...>(Case);
return asenum::AsEnum<T_Cases...>(Case, nullptr);
}

template <typename... T_Cases>
Expand Down Expand Up @@ -267,21 +274,9 @@ asenum::details::AsSwitch<typename asenum::AsEnum<T_Cases...>::Enum, asenum::AsE
// AsEnum private

template <typename... T_Cases>
template <typename T, typename RealT>
asenum::AsEnum<T_Cases...>::AsEnum(const Enum relatedCase, T&& value)
: m_enumCase(relatedCase)
, m_value(new RealT(std::forward<T>(value)), [] (void* ptr) {
if (ptr)
{
delete reinterpret_cast<RealT*>(ptr);
}
})
{}

template <typename... T_Cases>
asenum::AsEnum<T_Cases...>::AsEnum(const Enum relatedCase)
asenum::AsEnum<T_Cases...>::AsEnum(const Enum relatedCase, std::shared_ptr<void> value)
: m_enumCase(relatedCase)
, m_value(nullptr)
, m_value(value)
{}

template <typename... T_Cases>
Expand Down
158 changes: 80 additions & 78 deletions tests/AsEnumTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

#include <asenum/asenum.h>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include <string>

Expand All @@ -36,129 +36,131 @@ namespace
{
Unknown,
StringOpt,
BoolOpt
VoidOpt
};

ASENUM_DECLARE(TestAsEnum, TestEnum)
{
ASENUM_DEFINE_STRUCTORS();

ASENUM_CASE(Unknown, int);
ASENUM_CASE(StringOpt, std::string);
ASENUM_CASE(BoolOpt, bool);
};
using TestAsEnum = asenum::AsEnum<
asenum::Case11<TestEnum, TestEnum::Unknown, int>,
asenum::Case11<TestEnum, TestEnum::StringOpt, std::string>,
asenum::Case11<TestEnum, TestEnum::VoidOpt, void>
>;

static_assert(std::is_same<TestAsEnum::UnderlyingType<TestEnum::Unknown>, int>::value, "Invalid underlying type");
static_assert(std::is_same<TestAsEnum::UnderlyingType<TestEnum::StringOpt>, std::string>::value, "Invalid underlying type");
static_assert(std::is_same<TestAsEnum::UnderlyingType<TestEnum::BoolOpt>, bool>::value, "Invalid underlying type");
}

TEST(AsEnum, NamedGetter)
{
const TestAsEnum value1 = TestAsEnum::createStringOpt("test");
const TestAsEnum value2 = TestAsEnum::createBoolOpt(true);
const TestAsEnum value3 = TestAsEnum::createUnknown(-100500);

EXPECT_EQ(value1.type(), TestEnum::StringOpt);
EXPECT_EQ(value2.type(), TestEnum::BoolOpt);
EXPECT_EQ(value3.type(), TestEnum::Unknown);

EXPECT_EQ(value1.asStringOpt(), "test");
EXPECT_THROW(value1.asUnknown(), std::exception);
EXPECT_THROW(value1.asBoolOpt(), std::exception);

EXPECT_EQ(value2.asBoolOpt(), true);
EXPECT_THROW(value2.asUnknown(), std::exception);
EXPECT_THROW(value2.asStringOpt(), std::exception);

EXPECT_EQ(value3.asUnknown(), -100500);
EXPECT_THROW(value3.asStringOpt(), std::exception);
EXPECT_THROW(value3.asBoolOpt(), std::exception);

static_assert(std::is_same<TestAsEnum::UnderlyingType<TestEnum::VoidOpt>, void>::value, "Invalid underlying type");

static_assert(GTEST_ARRAY_SIZE_(TestAsEnum::AllCases) == 3, "Invalid number of cases");
static_assert(TestAsEnum::AllCases[0] == TestEnum::Unknown, "Invalid enum case");
static_assert(TestAsEnum::AllCases[1] == TestEnum::StringOpt, "Invalid enum case");
static_assert(TestAsEnum::AllCases[2] == TestEnum::VoidOpt, "Invalid enum case");
}

TEST(AsEnum, EnumGetter)
TEST(AsEnum, IfCase)
{
const TestAsEnum value1 = TestAsEnum::create<TestEnum::StringOpt>("test");
const TestAsEnum value2 = TestAsEnum::create<TestEnum::BoolOpt>(true);
const TestAsEnum value2 = TestAsEnum::create<TestEnum::VoidOpt>();
const TestAsEnum value3 = TestAsEnum::create<TestEnum::Unknown>(-100500);

EXPECT_EQ(value1.type(), TestEnum::StringOpt);
EXPECT_EQ(value2.type(), TestEnum::BoolOpt);
EXPECT_EQ(value3.type(), TestEnum::Unknown);
MockFunction<void(std::string)> handler1;
MockFunction<void(void)> handler2;
MockFunction<void(int)> handler3;

EXPECT_EQ(value1.as<TestEnum::StringOpt>(), "test");
EXPECT_THROW(value1.as<TestEnum::Unknown>(), std::exception);
EXPECT_THROW(value1.as<TestEnum::BoolOpt>(), std::exception);
EXPECT_CALL(handler1, Call("test"))
.WillOnce(Return());
EXPECT_CALL(handler2, Call())
.WillOnce(Return());
EXPECT_CALL(handler3, Call(-100500))
.WillOnce(Return());

EXPECT_EQ(value2.as<TestEnum::BoolOpt>(), true);
EXPECT_THROW(value2.as<TestEnum::Unknown>(), std::exception);
EXPECT_THROW(value2.as<TestEnum::StringOpt>(), std::exception);
EXPECT_TRUE(value1.ifCase<TestEnum::StringOpt>(handler1.AsStdFunction()));
EXPECT_FALSE(value1.ifCase<TestEnum::VoidOpt>(handler2.AsStdFunction()));
EXPECT_FALSE(value1.ifCase<TestEnum::Unknown>(handler3.AsStdFunction()));

EXPECT_EQ(value3.as<TestEnum::Unknown>(), -100500);
EXPECT_THROW(value3.as<TestEnum::StringOpt>(), std::exception);
EXPECT_THROW(value3.as<TestEnum::BoolOpt>(), std::exception);
EXPECT_FALSE(value2.ifCase<TestEnum::StringOpt>(handler1.AsStdFunction()));
EXPECT_TRUE(value2.ifCase<TestEnum::VoidOpt>(handler2.AsStdFunction()));
EXPECT_FALSE(value2.ifCase<TestEnum::Unknown>(handler3.AsStdFunction()));

EXPECT_FALSE(value3.ifCase<TestEnum::StringOpt>(handler1.AsStdFunction()));
EXPECT_FALSE(value3.ifCase<TestEnum::VoidOpt>(handler2.AsStdFunction()));
EXPECT_TRUE(value3.ifCase<TestEnum::Unknown>(handler3.AsStdFunction()));
}

TEST(AsEnum, Is)
TEST(AsEnum, IsCase)
{
const TestAsEnum value = TestAsEnum::create<TestEnum::StringOpt>("test");
const TestAsEnum value1 = TestAsEnum::create<TestEnum::StringOpt>("test");
const TestAsEnum value2 = TestAsEnum::create<TestEnum::VoidOpt>();
const TestAsEnum value3 = TestAsEnum::create<TestEnum::Unknown>(-100500);

EXPECT_EQ(value1.enumCase(), TestEnum::StringOpt);
EXPECT_EQ(value2.enumCase(), TestEnum::VoidOpt);
EXPECT_EQ(value3.enumCase(), TestEnum::Unknown);

EXPECT_TRUE(value.is<TestEnum::StringOpt>());
EXPECT_TRUE(value.isStringOpt());
EXPECT_TRUE(value1.isCase<TestEnum::StringOpt>());
EXPECT_FALSE(value1.isCase<TestEnum::VoidOpt>());
EXPECT_FALSE(value1.isCase<TestEnum::Unknown>());

EXPECT_FALSE(value.is<TestEnum::Unknown>());
EXPECT_FALSE(value.isUnknown());
EXPECT_FALSE(value2.isCase<TestEnum::StringOpt>());
EXPECT_TRUE(value2.isCase<TestEnum::VoidOpt>());
EXPECT_FALSE(value2.isCase<TestEnum::Unknown>());

EXPECT_FALSE(value.is<TestEnum::BoolOpt>());
EXPECT_FALSE(value.isBoolOpt());
EXPECT_FALSE(value3.isCase<TestEnum::StringOpt>());
EXPECT_FALSE(value3.isCase<TestEnum::VoidOpt>());
EXPECT_TRUE(value3.isCase<TestEnum::Unknown>());
}

TEST(AsEnum, Switch_Full)
{
const TestAsEnum value1 = TestAsEnum::createStringOpt("test");
const TestAsEnum value = TestAsEnum::create<TestEnum::StringOpt>("test");

value1.doSwitch()
.asCase<TestEnum::StringOpt>([] (const std::string& value) {
EXPECT_EQ(value, "test");
})
.asCase<TestEnum::BoolOpt>([] (const bool& value) {
MockFunction<void(std::string)> handler;

EXPECT_CALL(handler, Call("test"))
.WillOnce(Return());

value.doSwitch()
.ifCase<TestEnum::StringOpt>(handler.AsStdFunction())
.ifCase<TestEnum::VoidOpt>([] {
EXPECT_TRUE(false);
})
.asCase<TestEnum::Unknown>([] (const int& value) {
.ifCase<TestEnum::Unknown>([] (const int& value) {
EXPECT_TRUE(false);
})
.asDefault([] () {
.ifDefault([] () {
EXPECT_TRUE(false);
});
}

TEST(AsEnum, Switch_Partial)
{
const TestAsEnum value1 = TestAsEnum::createStringOpt("test");
const TestAsEnum value = TestAsEnum::create<TestEnum::StringOpt>("test");

value1.doSwitch()
.asCase<TestEnum::StringOpt>([] (const std::string& value) {
EXPECT_EQ(value, "test");
})
.asCase<TestEnum::BoolOpt>([] (const bool& value) {
MockFunction<void(std::string)> handler;

EXPECT_CALL(handler, Call("test"))
.WillOnce(Return());

value.doSwitch()
.ifCase<TestEnum::StringOpt>(handler.AsStdFunction())
.ifCase<TestEnum::VoidOpt>([] {
EXPECT_TRUE(false);
});
}

TEST(AsEnum, Switch_Default)
{
const TestAsEnum value1 = TestAsEnum::createStringOpt("test");
const TestAsEnum value = TestAsEnum::create<TestEnum::StringOpt>("test");

MockFunction<void(void)> handler;

EXPECT_CALL(handler, Call())
.WillOnce(Return());

value1.doSwitch()
.asCase<TestEnum::Unknown>([] (const int& value) {
value.doSwitch()
.ifCase<TestEnum::Unknown>([] (const int& value) {
EXPECT_TRUE(false);
})
.asCase<TestEnum::BoolOpt>([] (const bool& value) {
.ifCase<TestEnum::VoidOpt>([] {
EXPECT_TRUE(false);
})
.asDefault([] () {
EXPECT_TRUE(true);
});;
.ifDefault(handler.AsStdFunction());
}

0 comments on commit 71f6f6b

Please sign in to comment.