#include "common/FlagsEnum.hpp" #include "Test.hpp" using namespace chatterino; namespace { enum class BasicScoped : std::uint16_t { None = 0, Foo = 1 << 0, Bar = 1 << 1, Baz = 1 << 2, Qox = 1 << 3, Quux = 1 << 4, Corge = 1 << 5, Grault = 1 << 6, Garply = 1 << 7, Waldo = 1 << 8, Fred = 1 << 9, }; using BasicInt = std::underlying_type_t; enum BasicUnscoped : BasicInt { None = 0, Foo = 1 << 0, Bar = 1 << 1, Baz = 1 << 2, Qox = 1 << 3, Quux = 1 << 4, Corge = 1 << 5, Grault = 1 << 6, Garply = 1 << 7, Waldo = 1 << 8, Fred = 1 << 9, }; using Scoped = FlagsEnum; using Unscoped = FlagsEnum; } // namespace TEST(FlagsEnum, sizeAndAlign) { enum class U8 : std::uint8_t {}; enum class I8 : std::int8_t {}; enum class U16 : std::uint16_t {}; enum class I16 : std::int16_t {}; enum class U32 : std::uint32_t {}; enum class I32 : std::int32_t {}; enum class U64 : std::uint64_t {}; enum class I64 : std::int64_t {}; auto check = []() { return (((sizeof(T) == sizeof(FlagsEnum)) && ...) && ((alignof(T) == alignof(FlagsEnum)) && ...)); }; static_assert( check.template operator()()); } template consteval void testCtor() { using FE = FlagsEnum; using U = std::underlying_type_t; static_assert(FE{}.value() == E::None); static_assert(FE{E::Bar}.value() == E::Bar); static_assert( FE{E::Bar, E::Qox}.value() == static_cast(static_cast(E::Bar) | static_cast(E::Qox))); static_assert( FE{E::Bar, E::Bar, E::Qox}.value() == static_cast(static_cast(E::Bar) | static_cast(E::Qox))); } TEST(FlagsEnum, ctor) { testCtor(); testCtor(); } template consteval void testOperatorEq() { using FE = FlagsEnum; static_assert(FE{} == FE{}); static_assert(FE{E::Corge} == FE{E::Corge}); static_assert(FE{E::Corge, E::Garply} == FE{E::Garply, E::Corge}); static_assert(FE{} == E::None); static_assert(E::None == FE{}); static_assert(FE{E::Foo} == E::Foo); static_assert(E::Foo == FE{E::Foo}); } TEST(FlagsEnum, operatorEq) { testOperatorEq(); testOperatorEq(); } template consteval void testOperatorNeq() { using FE = FlagsEnum; static_assert(FE{} != FE{E::Quux}); static_assert(FE{E::Corge} != FE{E::Grault}); static_assert(FE{E::Corge, E::Garply} != FE{E::Garply, E::Waldo}); static_assert(FE{} != E::Foo); static_assert(E::Foo != FE{}); static_assert(FE{E::Foo} != E::None); static_assert(E::None != FE{E::Foo}); } TEST(FlagsEnum, operatorNeq) { testOperatorNeq(); testOperatorNeq(); } template inline void testSetUnset() { using FE = FlagsEnum; FE s; ASSERT_EQ(s, FE{}); s.set(E::Foo); ASSERT_EQ(s, E::Foo); s.set(E::Fred, E::Qox); ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox})); s.set(E::Foo); ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox})); s.set(FE{E::Bar, E::Baz, E::Qox}); ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox, E::Bar, E::Baz})); s.set(E::Foo, false); ASSERT_EQ(s, (FE{E::Fred, E::Qox, E::Bar, E::Baz})); s.unset(E::Foo, E::Qox, E::Bar); ASSERT_EQ(s, (FE{E::Fred, E::Baz})); s.unset(E::Fred, E::Baz, E ::Bar); ASSERT_EQ(s, FE{}); s.unset(E::Baz); ASSERT_EQ(s, FE{}); static_assert([] { FE s; bool result = s == FE{}; s.set(E::Foo); result = result && s == E::Foo; s.set(E::Fred, E::Qox); result = result && s == FE{E::Foo, E::Fred, E::Qox}; s.set(E::Foo); result = result && s == FE{E::Foo, E::Fred, E::Qox}; s.set(FE{E::Bar, E::Baz, E::Qox}); result = result && s == FE{E::Foo, E::Fred, E::Qox, E::Bar, E::Baz}; s.set(E::Foo, false); result = result && s == (FE{E::Fred, E::Qox, E::Bar, E::Baz}); s.unset(E::Foo, E::Qox, E::Bar); result = result && s == (FE{E::Fred, E::Baz}); s.unset(E::Fred, E::Baz, E ::Bar); result = result && s == (FE{}); s.unset(E::Baz); result = result && s == (FE{}); return result; }()); } TEST(FlagsEnum, setUnset) { testSetUnset(); testSetUnset(); } template consteval void testOperatorBitOr() { using FE = FlagsEnum; static_assert((FE{E::Foo} | E::Bar) == FE{E::Foo, E::Bar}); static_assert((FE{E::Foo} | E::Foo) == FE{E::Foo}); static_assert((FE{E::Foo} | E::None) == FE{E::Foo}); static_assert((FE{} | E::Foo) == FE{E::Foo}); static_assert((FE{} | E::None) == FE{}); static_assert((FE{E::Foo} | FE{E::Bar}) == FE{E::Foo, E::Bar}); static_assert((FE{E::Foo} | FE{E::Foo, E::Bar, E::Baz}) == FE{E::Foo, E::Bar, E::Baz}); static_assert((FE{E::Foo} | FE{}) == FE{E::Foo}); static_assert((FE{} | FE{}) == FE{}); } TEST(FlagsEnum, operatorBitOr) { testOperatorBitOr(); testOperatorBitOr(); } template consteval void testHas() { using FE = FlagsEnum; static_assert(FE{E::Foo}.has(E::Foo)); static_assert(!FE{E::Foo}.has(E::Bar)); static_assert(!FE{E::Foo}.has(E::None)); static_assert(!FE{}.has(E::Foo)); static_assert(!FE{}.has(E::None)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Qox)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Waldo)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Garply)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.has(E::Grault)); } TEST(FlagsEnum, has) { testHas(); testHas(); } template consteval void testHasAny() { using FE = FlagsEnum; static_assert(FE{E::Foo}.hasAny(E::Foo)); static_assert(!FE{E::Foo}.hasAny(E::Bar)); static_assert(!FE{E::Foo}.hasAny(E::None)); static_assert(!FE{}.hasAny(E::Foo)); static_assert(!FE{}.hasAny(E::None)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Qox, E::Foo)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny({E::Qox, E::Foo})); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Waldo, E::None)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Garply, E::Grault)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Grault)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAny()); } TEST(FlagsEnum, hasAny) { testHasAny(); testHasAny(); } template consteval void testHasAll() { using FE = FlagsEnum; static_assert(FE{E::Foo}.hasAll(E::Foo)); static_assert(FE{E::Foo}.hasAll(E::None)); static_assert(!FE{E::Foo}.hasAll(E::Bar)); static_assert(FE{}.hasAll(E::None)); static_assert(!FE{}.hasAll(E::Foo)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Waldo, E::None)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll({E::Waldo, E::None})); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll()); static_assert( FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, E::Garply)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, E::Garply, E::None)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Foo)); static_assert( !FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Garply, E::Grault)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Grault)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, E::Garply, E::Foo)); } TEST(FlagsEnum, hasAll) { testHasAll(); testHasAll(); } template consteval void testHasNone() { using FE = FlagsEnum; static_assert(FE{E::Foo}.hasNone(E::Bar)); static_assert(FE{E::Foo}.hasNone(E::None)); static_assert(FE{}.hasNone(E::Foo)); static_assert(FE{}.hasNone(E::None)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Foo, E::Foo)); static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasNone({E::Bar, E::Foo})); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Waldo, E::Foo)); static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Garply)); } TEST(FlagsEnum, hasNone) { testHasNone(); testHasNone(); } template consteval void testIsEmpty() { using FE = FlagsEnum; static_assert(FE{}.isEmpty()); static_assert(!FE{E::Foo}.isEmpty()); static_assert(FE{E::None}.isEmpty()); static_assert(!FE{E::Foo, E::Waldo}.isEmpty()); } TEST(FlagsEnum, isEmpty) { testIsEmpty(); testIsEmpty(); } template constexpr inline auto CONSTRUCTION_VALID = requires() { FlagsEnum{}; }; TEST(FlagsEnum, templateParam) { struct S { }; static_assert(!CONSTRUCTION_VALID); static_assert(!CONSTRUCTION_VALID); static_assert(!CONSTRUCTION_VALID); static_assert(!CONSTRUCTION_VALID); static_assert(!CONSTRUCTION_VALID); static_assert(CONSTRUCTION_VALID); static_assert(CONSTRUCTION_VALID); }