Anton Bachin 2acb5743fa Complete documentation and testing overhaul.
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.
2015-05-27 09:58:34 -05:00

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);
}
};