mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
The documentation is now generated from markdown. Samples are generated from the tutorial pages. Testing is done by a Python script which runs the tests for a large number of compilers. This version is not very developer-friendly - the Python scripts need ways of limiting what compilers they try to run. If you don't have 15 compilers installed, you won't be able to run the tests in this commit. Fix coming soon.
273 lines
9.9 KiB
C++
273 lines
9.9 KiB
C++
#include <stdexcept>
|
|
#include <cxxtest/TestSuite.h>
|
|
#include <enum.h>
|
|
|
|
#define static_assert_1(e) static_assert(e, #e)
|
|
|
|
#ifdef BETTER_ENUMS_STRICT_CONVERSION
|
|
# define STRICT 1
|
|
#else
|
|
# define STRICT 0
|
|
#endif
|
|
|
|
|
|
|
|
ENUM(Channel, short, Red, Green, Blue)
|
|
ENUM(Depth, short, HighColor = 40, TrueColor = 20)
|
|
ENUM(Compression, short, None, Huffman, Default = Huffman)
|
|
|
|
|
|
|
|
// Using _ENUM_HAVE_CONSTEXPR as a proxy for C++11 support. This should be
|
|
// changed to be more precise in the future.
|
|
#ifdef _ENUM_HAVE_CONSTEXPR
|
|
|
|
#include <type_traits>
|
|
|
|
// Type properties.
|
|
static_assert_1(std::is_class<Channel>());
|
|
static_assert_1(std::is_standard_layout<Channel>());
|
|
static_assert_1(std::is_literal_type<Channel>());
|
|
|
|
|
|
|
|
// Member type properties and identities.
|
|
static_assert_1(std::is_integral<Channel::_integral>());
|
|
static_assert_1(std::is_enum<Channel::_enumerated>());
|
|
|
|
static_assert_1((std::is_same<short, Channel::_integral>()));
|
|
static_assert_1((std::is_same<
|
|
short, std::underlying_type<Channel::_enumerated>::type>()));
|
|
|
|
static_assert_1(!(std::is_same<int, Channel::_integral>()));
|
|
static_assert_1(!(std::is_same<
|
|
int, std::underlying_type<Channel::_enumerated>::type>()));
|
|
|
|
static_assert_1(sizeof(Channel) == sizeof(short));
|
|
static_assert_1(alignof(Channel) == alignof(short));
|
|
|
|
static_assert_1((std::is_same<decltype(Channel::Red), Channel::_enumerated>()));
|
|
|
|
|
|
|
|
// Supported constructors.
|
|
|
|
#ifdef __clang__
|
|
static_assert_1(std::is_trivially_copyable<Channel>());
|
|
#endif
|
|
|
|
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
|
|
static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
|
|
static_assert_1(!(std::is_constructible<Channel, Depth>()));
|
|
|
|
// Commented out temporarily due to GCC 4.7- bug.
|
|
// static_assert_1(!std::is_default_constructible<Channel>());
|
|
|
|
|
|
|
|
// Intended implicit conversions.
|
|
static_assert_1((std::is_convertible<Channel::_enumerated, Channel>()));
|
|
|
|
// Regrettable implicit conversions.
|
|
static_assert_1((std::is_convertible<decltype(Channel::Red),
|
|
Channel::_integral>()));
|
|
|
|
// Disallowed implicit conversions.
|
|
static_assert_1(!(std::is_convertible<Channel::_integral, Channel>()));
|
|
static_assert_1(!(std::is_convertible<Depth, Channel>()));
|
|
static_assert_1(!(std::is_convertible<Channel, Depth>()));
|
|
|
|
// Controllable implicit conversions.
|
|
static_assert_1(
|
|
(std::is_convertible<Channel, Channel::_integral>() != STRICT));
|
|
static_assert_1(
|
|
(std::is_convertible<Channel, Channel::_enumerated>() != STRICT));
|
|
static_assert_1(
|
|
(std::is_convertible<decltype(+Channel::Red), Channel::_integral>()
|
|
!= STRICT));
|
|
static_assert_1(
|
|
(std::is_convertible<decltype(Channel::_values()[0]), Channel::_integral>()
|
|
!= 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);
|
|
|
|
#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
|
|
|
|
|
|
|
|
// Run-time testing.
|
|
class EnumTests : public CxxTest::TestSuite {
|
|
public:
|
|
void test_constant_values()
|
|
{
|
|
TS_ASSERT_EQUALS((+Channel::Red)._to_integral(), 0);
|
|
TS_ASSERT_EQUALS((+Channel::Green)._to_integral(), 1);
|
|
TS_ASSERT_EQUALS((+Channel::Blue)._to_integral(), 2);
|
|
TS_ASSERT_EQUALS((+Depth::HighColor)._to_integral(), 40);
|
|
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_integral(), 20);
|
|
}
|
|
|
|
void test_integral_conversions()
|
|
{
|
|
TS_ASSERT_EQUALS(Channel::_from_integral(1), +Channel::Green);
|
|
TS_ASSERT_DIFFERS(Channel::_from_integral(1), +Channel::Blue);
|
|
TS_ASSERT_EQUALS(Channel::_from_integral_unchecked(1), +Channel::Green);
|
|
TS_ASSERT_DIFFERS(Channel::_from_integral_unchecked(1), +Channel::Blue);
|
|
|
|
TS_ASSERT_THROWS(Channel::_from_integral(3), std::runtime_error);
|
|
TS_ASSERT_THROWS_NOTHING(Channel::_from_integral_unchecked(3));
|
|
|
|
better_enums::optional<Channel> maybe_channel =
|
|
Channel::_from_integral_nothrow(2);
|
|
TS_ASSERT(maybe_channel);
|
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
|
|
TS_ASSERT(!Channel::_from_integral_nothrow(3));
|
|
|
|
TS_ASSERT(Channel::_is_valid((Channel::_integral)0));
|
|
TS_ASSERT(Channel::_is_valid(1));
|
|
TS_ASSERT(Channel::_is_valid(2));
|
|
TS_ASSERT(!Channel::_is_valid(3));
|
|
}
|
|
|
|
void test_string_conversions()
|
|
{
|
|
TS_ASSERT_EQUALS(strcmp((+Channel::Green)._to_string(), "Green"), 0);
|
|
TS_ASSERT_EQUALS(strcmp((+Depth::HighColor)._to_string(),
|
|
"HighColor"), 0);
|
|
|
|
TS_ASSERT_EQUALS(Channel::_from_string("Green"), +Channel::Green);
|
|
TS_ASSERT_DIFFERS(Channel::_from_string("Green"), +Channel::Blue);
|
|
TS_ASSERT_EQUALS(Channel::_from_string("Blue"), +Channel::Blue);
|
|
TS_ASSERT_DIFFERS(Channel::_from_string("Blue"), +Channel::Green);
|
|
TS_ASSERT_THROWS(Channel::_from_string("green"), std::runtime_error);
|
|
|
|
better_enums::optional<Channel> maybe_channel =
|
|
Channel::_from_string_nothrow("Green");
|
|
TS_ASSERT(maybe_channel);
|
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
|
|
TS_ASSERT(!Channel::_from_string_nothrow("green"));
|
|
|
|
TS_ASSERT_EQUALS(Channel::_from_string_nocase("green"),
|
|
+Channel::Green);
|
|
TS_ASSERT_DIFFERS(Channel::_from_string_nocase("green"),
|
|
+Channel::Blue);
|
|
TS_ASSERT_EQUALS(Channel::_from_string_nocase("blue"),
|
|
+Channel::Blue);
|
|
TS_ASSERT_DIFFERS(Channel::_from_string_nocase("blue"),
|
|
+Channel::Green);
|
|
TS_ASSERT_THROWS(Channel::_from_string_nocase("a"), std::runtime_error);
|
|
|
|
maybe_channel = Channel::_from_string_nocase_nothrow("green");
|
|
TS_ASSERT(maybe_channel);
|
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
|
|
TS_ASSERT(!Channel::_from_string_nocase_nothrow("greeen"));
|
|
|
|
TS_ASSERT(Channel::_is_valid("Green"));
|
|
TS_ASSERT(!Channel::_is_valid("green"));
|
|
TS_ASSERT(Channel::_is_valid_nocase("green"));
|
|
TS_ASSERT(!Channel::_is_valid_nocase("greeen"));
|
|
}
|
|
|
|
void test_value_iterable()
|
|
{
|
|
TS_ASSERT_EQUALS(Channel::_size, 3);
|
|
TS_ASSERT_EQUALS(Depth::_size, 2);
|
|
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
|
|
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
|
|
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
|
|
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
|
|
TS_ASSERT_EQUALS(Channel::_values()[1], +Channel::Green);
|
|
TS_ASSERT_EQUALS(Channel::_values()[2], +Channel::Blue);
|
|
|
|
Channel::_value_iterator value_iterator = Channel::_values().begin();
|
|
TS_ASSERT_EQUALS(*value_iterator, +Channel::Red);
|
|
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
|
|
|
++value_iterator;
|
|
TS_ASSERT_EQUALS(*value_iterator, +Channel::Green);
|
|
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
|
|
|
++value_iterator;
|
|
TS_ASSERT_EQUALS(*value_iterator, +Channel::Blue);
|
|
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
|
|
|
++value_iterator;
|
|
TS_ASSERT_EQUALS(value_iterator, Channel::_values().end());
|
|
}
|
|
|
|
void test_name_iterable()
|
|
{
|
|
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size);
|
|
TS_ASSERT_EQUALS(strcmp(*Channel::_names().begin(), "Red"), 0);
|
|
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
|
|
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
|
|
|
|
Channel::_name_iterator name_iterator = Channel::_names().begin();
|
|
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Red"), 0);
|
|
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
|
|
|
++name_iterator;
|
|
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Green"), 0);
|
|
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
|
|
|
++name_iterator;
|
|
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Blue"), 0);
|
|
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
|
|
|
++name_iterator;
|
|
TS_ASSERT_EQUALS(name_iterator, Channel::_names().end());
|
|
}
|
|
|
|
void test_type_name()
|
|
{
|
|
TS_ASSERT_EQUALS(strcmp(Channel::_name(), "Channel"), 0);
|
|
TS_ASSERT_EQUALS(strcmp(Depth::_name(), "Depth"), 0);
|
|
TS_ASSERT_EQUALS(strcmp(Compression::_name(), "Compression"), 0);
|
|
}
|
|
|
|
void test_alias()
|
|
{
|
|
TS_ASSERT_EQUALS(Compression::Default, Compression::Huffman);
|
|
}
|
|
};
|