#define CATCH_CONFIG_MAIN #include #include #include #define MAIN_TAG "[better-enums]" BETTER_ENUM(Channel, short, Red, Green, Blue) BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20) BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman) namespace test { BETTER_ENUM(Namespaced, short, One, Two) } // Using BETTER_ENUMS_HAVE_CONSTEXPR_ as a proxy for C++11 support. This should // be changed to be more precise in the future. #ifdef BETTER_ENUMS_HAVE_CONSTEXPR_ // Type properties. static_assert_1(std::is_class()); static_assert_1(std::is_standard_layout()); static_assert_1(std::is_literal_type()); // Member type properties and identities. static_assert_1(std::is_integral()); static_assert_1(std::is_enum()); static_assert_1((std::is_same())); // Temporarily disabled due to outdated libraries in Travis. // static_assert_1((std::is_same< // short, std::underlying_type::type>())); static_assert_1(!(std::is_same())); // Temporarily disabled due to outdated libraries in Travis. // static_assert_1(!(std::is_same< // int, std::underlying_type::type>())); static_assert_1(sizeof(Channel) == sizeof(short)); static_assert_1(alignof(Channel) == alignof(short)); static_assert_1((std::is_same())); // Supported constructors. // Apparently, this isn't supported by Clang in Travis. // #ifdef __clang__ // static_assert_1(std::is_trivially_copyable()); // #endif static_assert_1((std::is_constructible())); // "Passes" by causing a compilation error. // static_assert_1(!(std::is_constructible())); // "Passes" on most compilers, passes on g++47 by causing a compilation error. // static_assert_1(!(std::is_constructible())); // Commented out temporarily due to GCC 4.7- bug. // static_assert_1(!std::is_default_constructible()); // Intended implicit conversions. static_assert_1((std::is_convertible())); // Regrettable implicit conversions. static_assert_1((std::is_convertible())); // Disallowed implicit conversions. static_assert_1(!(std::is_convertible())); static_assert_1(!(std::is_convertible())); static_assert_1(!(std::is_convertible())); // Controllable implicit conversions. static_assert_1( (std::is_convertible() != STRICT)); static_assert_1( (std::is_convertible() != STRICT)); static_assert_1( (std::is_convertible() != STRICT)); static_assert_1( (std::is_convertible() != STRICT)); static_assert_1((+Depth::HighColor)._to_integral() == 40); static_assert_1(Depth::_from_integral(40) == +Depth::HighColor); static_assert_1(Depth::_from_integral_unchecked(40) == +Depth::HighColor); static_assert_1(Depth::_from_integral_nothrow(40)); static_assert_1(*Depth::_from_integral_nothrow(40) == +Depth::HighColor); static_assert_1(Depth::_is_valid(40)); static_assert_1(Channel::_from_string("Green") == +Channel::Green); static_assert_1(Channel::_from_string_nocase("green") == +Channel::Green); static_assert_1(*Channel::_from_string_nothrow("Green") == +Channel::Green); static_assert_1( *Channel::_from_string_nocase_nothrow("green") == +Channel::Green); static_assert_1(Channel::_is_valid("Green")); static_assert_1(Channel::_is_valid_nocase("green")); static_assert_1(Channel::_size() == 3); static_assert_1(Channel::_values().size() == 3); static_assert_1(*Channel::_values().begin() == +Channel::Red); static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue); static_assert_1(Channel::_values()[1] == +Channel::Green); namespace name_clash_test { struct Foo {}; std::ostream& operator<<(std::ostream&, Foo); BETTER_ENUM(Enum, int, ONE, TWO, THREE) static_assert_1((std::is_same() << +Enum::ONE), std::ostream&>())); } #ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING constexpr bool same_string(const char *r, const char *s, size_t index = 0) { return r[index] == '\0' ? s[index] == '\0' : s[index] == '\0' ? false : r[index] != s[index] ? false : same_string(r, s, index + 1); } static_assert_1(same_string((+Depth::HighColor)._to_string(), "HighColor")); static_assert_1(Depth::_names().size() == 2); static_assert_1(same_string(*Depth::_names().begin(), "HighColor")); static_assert_1(same_string(*(Depth::_names().end() - 1), "TrueColor")); static_assert_1(same_string(Depth::_names()[0], "HighColor")); #endif // #ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING #endif // #ifdef _ENUM_HAVE_CONSTEXPR TEST_CASE("test constant values", MAIN_TAG) { CHECK((+Channel::Red)._to_integral() == 0); CHECK((+Channel::Green)._to_integral() == 1); CHECK((+Channel::Blue)._to_integral() == 2); CHECK((+Depth::HighColor)._to_integral() == 40); CHECK((+Depth::TrueColor)._to_integral() == 20); } TEST_CASE("test integral conversions", MAIN_TAG) { CHECK(Channel::_from_integral(1) == +Channel::Green); CHECK(Channel::_from_integral(1) != +Channel::Blue); CHECK(Channel::_from_integral_unchecked(1) == +Channel::Green); CHECK(Channel::_from_integral_unchecked(1) != +Channel::Blue); CHECK_THROWS_AS(Channel::_from_integral(3), std::runtime_error); CHECK_NOTHROW(Channel::_from_integral_unchecked(3)); better_enums::optional maybe_channel = Channel::_from_integral_nothrow(2); CHECK(maybe_channel); CHECK(*maybe_channel == +Channel::Blue); CHECK(!Channel::_from_integral_nothrow(3)); CHECK(Channel::_is_valid((Channel::_integral)0)); CHECK(Channel::_is_valid(1)); CHECK(Channel::_is_valid(2)); CHECK(!Channel::_is_valid(3)); } TEST_CASE("test string conversions", MAIN_TAG) { CHECK(strcmp((+Channel::Green)._to_string(), "Green") == 0); CHECK(strcmp((+Depth::HighColor)._to_string(), "HighColor") == 0); CHECK(Channel::_from_string("Green") == +Channel::Green); CHECK(Channel::_from_string("Green") != +Channel::Blue); CHECK(Channel::_from_string("Blue") == +Channel::Blue); CHECK(Channel::_from_string("Blue") != +Channel::Green); CHECK_THROWS_AS(Channel::_from_string("green"), std::runtime_error); better_enums::optional maybe_channel = Channel::_from_string_nothrow("Green"); CHECK(maybe_channel); CHECK(*maybe_channel == +Channel::Green); CHECK(!Channel::_from_string_nothrow("green")); CHECK(Channel::_from_string_nocase("green") == +Channel::Green); CHECK(Channel::_from_string_nocase("green") != +Channel::Blue); CHECK(Channel::_from_string_nocase("blue") == +Channel::Blue); CHECK(Channel::_from_string_nocase("blue") != +Channel::Green); CHECK_THROWS_AS(Channel::_from_string_nocase("a"), std::runtime_error); maybe_channel = Channel::_from_string_nocase_nothrow("green"); CHECK(maybe_channel); CHECK(*maybe_channel == +Channel::Green); CHECK(!Channel::_from_string_nocase_nothrow("greeen")); CHECK(Channel::_is_valid("Green")); CHECK(!Channel::_is_valid("green")); CHECK(Channel::_is_valid_nocase("green")); CHECK(!Channel::_is_valid_nocase("greeen")); } TEST_CASE("test value iterable", MAIN_TAG) { CHECK(Channel::_size() == 3); CHECK(Depth::_size() == 2); CHECK(Channel::_values().size() == Channel::_size()); CHECK(*Channel::_values().begin() == +Channel::Red); CHECK(*(Channel::_values().begin() + 1) == +Channel::Green); CHECK(*(Channel::_values().begin() + 2) == +Channel::Blue); CHECK(Channel::_values()[1] == +Channel::Green); CHECK(Channel::_values()[2] == +Channel::Blue); Channel::_value_iterator value_iterator = Channel::_values().begin(); CHECK(*value_iterator == +Channel::Red); CHECK(value_iterator != Channel::_values().end()); ++value_iterator; CHECK(*value_iterator == +Channel::Green); CHECK(value_iterator != Channel::_values().end()); ++value_iterator; CHECK(*value_iterator == +Channel::Blue); CHECK(value_iterator != Channel::_values().end()); ++value_iterator; CHECK(value_iterator == Channel::_values().end()); } TEST_CASE("test name iterable", MAIN_TAG) { CHECK(Channel::_names().size() == Channel::_size()); CHECK(strcmp(*Channel::_names().begin(), "Red") == 0); CHECK(strcmp(Channel::_names()[0], "Red") == 0); CHECK(strcmp(Depth::_names()[0], "HighColor") == 0); Channel::_name_iterator name_iterator = Channel::_names().begin(); CHECK(strcmp(*name_iterator, "Red") == 0); CHECK(name_iterator != Channel::_names().end()); ++name_iterator; CHECK(strcmp(*name_iterator, "Green") == 0); CHECK(name_iterator != Channel::_names().end()); ++name_iterator; CHECK(strcmp(*name_iterator, "Blue") == 0); CHECK(name_iterator != Channel::_names().end()); ++name_iterator; CHECK(name_iterator == Channel::_names().end()); } TEST_CASE("test type name", MAIN_TAG) { CHECK(strcmp(Channel::_name(), "Channel") == 0); CHECK(strcmp(Depth::_name(), "Depth") == 0); CHECK(strcmp(Compression::_name(), "Compression") == 0); } /// @todo This test case is failing and is currently deemed invalid /// at this time. /// /// @see https://github.com/aantron/better-enums/issues/24 /* TEST_CASE("test alias", MAIN_TAG) { CHECK(Compression::Default == Compression::Huffman); } */ TEST_CASE("test namespaced", MAIN_TAG) { CHECK((+test::Namespaced::One)._to_integral() == 0); CHECK(test::Namespaced::_from_integral(0) == +test::Namespaced::One); CHECK(strcmp((+test::Namespaced::One)._to_string(), "One") == 0); CHECK(test::Namespaced::_from_string("Two") == +test::Namespaced::Two); CHECK(test::Namespaced::_values()[0] == +test::Namespaced::One); CHECK(strcmp(test::Namespaced::_names()[0], "One") == 0); CHECK(*test::Namespaced::_values().begin() == +test::Namespaced::One); CHECK(strcmp(*test::Namespaced::_names().begin(), "One") == 0); } BETTER_ENUM(Compiler, int, GCC, Clang, MSVC) TEST_CASE("test stream output", MAIN_TAG) { std::ostringstream stream; stream << +Compiler::GCC; CHECK(stream.str() == "GCC"); } TEST_CASE("test stream input", MAIN_TAG) { std::istringstream stream("Clang"); Compiler compiler = Compiler::GCC; stream >> compiler; CHECK(compiler == +Compiler::Clang); } BETTER_ENUM(InternalNameCollisions, int, EnumClassForSwitchStatements, PutNamesInThisScopeAlso, force_initialization, value_array, raw_names, name_storage, name_array, initialized, the_raw_names, the_name_array)