summaryrefslogtreecommitdiffstats
path: root/mfbt/tests/TestTypedEnum.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests/TestTypedEnum.cpp')
-rw-r--r--mfbt/tests/TestTypedEnum.cpp556
1 files changed, 556 insertions, 0 deletions
diff --git a/mfbt/tests/TestTypedEnum.cpp b/mfbt/tests/TestTypedEnum.cpp
new file mode 100644
index 000000000..43c36f2b8
--- /dev/null
+++ b/mfbt/tests/TestTypedEnum.cpp
@@ -0,0 +1,556 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/TypedEnumBits.h"
+
+#include <stdint.h>
+
+// A rough feature check for is_literal_type. Not very carefully checked.
+// Feel free to amend as needed.
+// We leave ANDROID out because it's using stlport which doesn't have std::is_literal_type.
+#if __cplusplus >= 201103L && !defined(ANDROID)
+# if defined(__clang__)
+ /*
+ * Per Clang documentation, "Note that marketing version numbers should not
+ * be used to check for language features, as different vendors use different
+ * numbering schemes. Instead, use the feature checking macros."
+ */
+# ifndef __has_extension
+# define __has_extension __has_feature /* compatibility, for older versions of clang */
+# endif
+# if __has_extension(is_literal) && __has_include(<type_traits>)
+# define MOZ_HAVE_IS_LITERAL
+# endif
+# elif defined(__GNUC__) || defined(_MSC_VER)
+# define MOZ_HAVE_IS_LITERAL
+# endif
+#endif
+
+#if defined(MOZ_HAVE_IS_LITERAL) && defined(MOZ_HAVE_CXX11_CONSTEXPR)
+#include <type_traits>
+template<typename T>
+void
+RequireLiteralType()
+{
+ static_assert(std::is_literal_type<T>::value, "Expected a literal type");
+}
+#else // not MOZ_HAVE_IS_LITERAL
+template<typename T>
+void
+RequireLiteralType()
+{
+}
+#endif
+
+template<typename T>
+void
+RequireLiteralType(const T&)
+{
+ RequireLiteralType<T>();
+}
+
+enum class AutoEnum {
+ A,
+ B = -3,
+ C
+};
+
+enum class CharEnum : char {
+ A,
+ B = 3,
+ C
+};
+
+enum class AutoEnumBitField {
+ A = 0x10,
+ B = 0x20,
+ C
+};
+
+enum class CharEnumBitField : char {
+ A = 0x10,
+ B,
+ C = 0x40
+};
+
+struct Nested
+{
+ enum class AutoEnum {
+ A,
+ B,
+ C = -1
+ };
+
+ enum class CharEnum : char {
+ A = 4,
+ B,
+ C = 1
+ };
+
+ enum class AutoEnumBitField {
+ A,
+ B = 0x20,
+ C
+ };
+
+ enum class CharEnumBitField : char {
+ A = 1,
+ B = 1,
+ C = 1
+ };
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField)
+
+#define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \
+ enum class BitFieldFor_##IntType : IntType { \
+ A = 1, \
+ B = 2, \
+ C = 4, \
+ }; \
+ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType)
+
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(char)
+typedef signed char signed_char;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char)
+typedef unsigned char unsigned_char;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(short)
+typedef unsigned short unsigned_short;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int)
+typedef unsigned int unsigned_int;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(long)
+typedef unsigned long unsigned_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long)
+typedef long long long_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long)
+typedef unsigned long long unsigned_long_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long)
+
+#undef MAKE_STANDARD_BITFIELD_FOR_TYPE
+
+template<typename T>
+void
+TestNonConvertibilityForOneType()
+{
+ using mozilla::IsConvertible;
+
+ static_assert(!IsConvertible<T, bool>::value, "should not be convertible");
+ static_assert(!IsConvertible<T, int>::value, "should not be convertible");
+ static_assert(!IsConvertible<T, uint64_t>::value, "should not be convertible");
+
+ static_assert(!IsConvertible<bool, T>::value, "should not be convertible");
+ static_assert(!IsConvertible<int, T>::value, "should not be convertible");
+ static_assert(!IsConvertible<uint64_t, T>::value, "should not be convertible");
+}
+
+template<typename TypedEnum>
+void
+TestTypedEnumBasics()
+{
+ const TypedEnum a = TypedEnum::A;
+ int unused = int(a);
+ (void) unused;
+ RequireLiteralType(TypedEnum::A);
+ RequireLiteralType(a);
+ TestNonConvertibilityForOneType<TypedEnum>();
+}
+
+// Op wraps a bitwise binary operator, passed as a char template parameter,
+// and applies it to its arguments (aT1, aT2). For example,
+//
+// Op<'|'>(aT1, aT2)
+//
+// is the same as
+//
+// aT1 | aT2.
+//
+template<char o, typename T1, typename T2>
+auto Op(const T1& aT1, const T2& aT2)
+ -> decltype(aT1 | aT2) // See the static_assert's below --- the return type
+ // depends solely on the operands type, not on the
+ // choice of operation.
+{
+ using mozilla::IsSame;
+ static_assert(IsSame<decltype(aT1 | aT2), decltype(aT1 & aT2)>::value,
+ "binary ops should have the same result type");
+ static_assert(IsSame<decltype(aT1 | aT2), decltype(aT1 ^ aT2)>::value,
+ "binary ops should have the same result type");
+
+ static_assert(o == '|' ||
+ o == '&' ||
+ o == '^', "unexpected operator character");
+
+ return o == '|' ? aT1 | aT2
+ : o == '&' ? aT1 & aT2
+ : aT1 ^ aT2;
+}
+
+// OpAssign wraps a bitwise binary operator, passed as a char template
+// parameter, and applies the corresponding compound-assignment operator to its
+// arguments (aT1, aT2). For example,
+//
+// OpAssign<'|'>(aT1, aT2)
+//
+// is the same as
+//
+// aT1 |= aT2.
+//
+template<char o, typename T1, typename T2>
+T1& OpAssign(T1& aT1, const T2& aT2)
+{
+ static_assert(o == '|' ||
+ o == '&' ||
+ o == '^', "unexpected operator character");
+
+ switch (o) {
+ case '|': return aT1 |= aT2;
+ case '&': return aT1 &= aT2;
+ case '^': return aT1 ^= aT2;
+ default: MOZ_CRASH();
+ }
+}
+
+// Tests a single binary bitwise operator, using a single set of three operands.
+// The operations tested are:
+//
+// result = aT1 Op aT2;
+// result Op= aT3;
+//
+// Where Op is the operator specified by the char template parameter 'o' and
+// can be any of '|', '&', '^'.
+//
+// Note that the operands aT1, aT2, aT3 are intentionally passed with free
+// types (separate template parameters for each) because their type may
+// actually be different from TypedEnum:
+//
+// 1) Their type could be CastableTypedEnumResult<TypedEnum> if they are
+// the result of a bitwise operation themselves;
+// 2) In the non-c++11 legacy path, the type of enum values is also
+// different from TypedEnum.
+//
+template<typename TypedEnum, char o, typename T1, typename T2, typename T3>
+void TestBinOp(const T1& aT1, const T2& aT2, const T3& aT3)
+{
+ typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
+ UnsignedIntegerType;
+
+ // Part 1:
+ // Test the bitwise binary operator i.e.
+ // result = aT1 Op aT2;
+ auto result = Op<o>(aT1, aT2);
+
+ typedef decltype(result) ResultType;
+
+ RequireLiteralType<ResultType>();
+ TestNonConvertibilityForOneType<ResultType>();
+
+ UnsignedIntegerType unsignedIntegerResult =
+ Op<o>(UnsignedIntegerType(aT1), UnsignedIntegerType(aT2));
+
+ MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
+ MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
+ MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
+ MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
+ MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
+
+ // Part 2:
+ // Test the compound-assignment operator, i.e.
+ // result Op= aT3;
+ TypedEnum newResult = result;
+ OpAssign<o>(newResult, aT3);
+ UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult;
+ OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(aT3));
+ MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult);
+
+ // Part 3:
+ // Test additional boolean operators that we unfortunately had to add to
+ // CastableTypedEnumResult at some point to please some compiler,
+ // even though bool convertibility should have been enough.
+ MOZ_RELEASE_ASSERT(result == TypedEnum(result));
+ MOZ_RELEASE_ASSERT(!(result != TypedEnum(result)));
+ MOZ_RELEASE_ASSERT((result && true) == bool(result));
+ MOZ_RELEASE_ASSERT((result && false) == false);
+ MOZ_RELEASE_ASSERT((true && result) == bool(result));
+ MOZ_RELEASE_ASSERT((false && result && false) == false);
+ MOZ_RELEASE_ASSERT((result || false) == bool(result));
+ MOZ_RELEASE_ASSERT((result || true) == true);
+ MOZ_RELEASE_ASSERT((false || result) == bool(result));
+ MOZ_RELEASE_ASSERT((true || result) == true);
+}
+
+// Similar to TestBinOp but testing the unary ~ operator.
+template<typename TypedEnum, typename T>
+void TestTilde(const T& aT)
+{
+ typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
+ UnsignedIntegerType;
+
+ auto result = ~aT;
+
+ typedef decltype(result) ResultType;
+
+ RequireLiteralType<ResultType>();
+ TestNonConvertibilityForOneType<ResultType>();
+
+ UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(aT));
+
+ MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
+ MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
+ MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
+ MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
+ MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
+}
+
+// Helper dispatching a given triple of operands to all operator-specific
+// testing functions.
+template<typename TypedEnum, typename T1, typename T2, typename T3>
+void TestAllOpsForGivenOperands(const T1& aT1, const T2& aT2, const T3& aT3)
+{
+ TestBinOp<TypedEnum, '|'>(aT1, aT2, aT3);
+ TestBinOp<TypedEnum, '&'>(aT1, aT2, aT3);
+ TestBinOp<TypedEnum, '^'>(aT1, aT2, aT3);
+ TestTilde<TypedEnum>(aT1);
+}
+
+// Helper building various triples of operands using a given operator,
+// and testing all operators with them.
+template<typename TypedEnum, char o>
+void TestAllOpsForOperandsBuiltUsingGivenOp()
+{
+ // The type of enum values like TypedEnum::A may be different from
+ // TypedEnum. That is the case in the legacy non-C++11 path. We want to
+ // ensure good test coverage even when these two types are distinct.
+ // To that effect, we have both 'auto' typed variables, preserving the
+ // original type of enum values, and 'plain' typed variables, that
+ // are plain TypedEnum's.
+
+ const TypedEnum a_plain = TypedEnum::A;
+ const TypedEnum b_plain = TypedEnum::B;
+ const TypedEnum c_plain = TypedEnum::C;
+
+ auto a_auto = TypedEnum::A;
+ auto b_auto = TypedEnum::B;
+ auto c_auto = TypedEnum::C;
+
+ auto ab_plain = Op<o>(a_plain, b_plain);
+ auto bc_plain = Op<o>(b_plain, c_plain);
+ auto ab_auto = Op<o>(a_auto, b_auto);
+ auto bc_auto = Op<o>(b_auto, c_auto);
+
+ // On each row below, we pass a triple of operands. Keep in mind that this
+ // is going to be received as (aT1, aT2, aT3) and the actual tests performed
+ // will be of the form
+ //
+ // result = aT1 Op aT2;
+ // result Op= aT3;
+ //
+ // For this reason, we carefully ensure that the values of (aT1, aT2)
+ // systematically cover all types of such pairs; to limit complexity,
+ // we are not so careful with aT3, and we just try to pass aT3's
+ // that may lead to nontrivial bitwise operations.
+ TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_plain, c_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_plain, b_auto);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain, a_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto);
+
+ TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_auto, c_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_auto, b_auto);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto, a_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto, a_auto);
+
+ TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_plain, c_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_plain, b_auto);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_plain, a_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_plain, a_auto);
+
+ TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_auto, c_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_auto, b_auto);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_auto, a_plain);
+ TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_auto, a_auto);
+}
+
+// Tests all bitwise operations on a given TypedEnum bitfield.
+template<typename TypedEnum>
+void
+TestTypedEnumBitField()
+{
+ TestTypedEnumBasics<TypedEnum>();
+
+ TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>();
+ TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>();
+ TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>();
+}
+
+// Checks that enum bitwise expressions have the same non-convertibility
+// properties as c++11 enum classes do, i.e. not implicitly convertible to
+// anything (though *explicitly* convertible).
+void TestNoConversionsBetweenUnrelatedTypes()
+{
+ using mozilla::IsConvertible;
+
+ // Two typed enum classes having the same underlying integer type, to ensure
+ // that we would catch bugs accidentally allowing conversions in that case.
+ typedef CharEnumBitField T1;
+ typedef Nested::CharEnumBitField T2;
+
+ static_assert(!IsConvertible<T1, T2>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<T1, decltype(T2::A)>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<T1, decltype(T2::A | T2::B)>::value,
+ "should not be convertible");
+
+ static_assert(!IsConvertible<decltype(T1::A), T2>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A)>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A | T2::B)>::value,
+ "should not be convertible");
+
+ static_assert(!IsConvertible<decltype(T1::A | T1::B), T2>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A)>::value,
+ "should not be convertible");
+ static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>::value,
+ "should not be convertible");
+}
+
+enum class Int8EnumWithHighBits : int8_t {
+ A = 0x20,
+ B = 0x40
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits)
+
+enum class Uint8EnumWithHighBits : uint8_t {
+ A = 0x40,
+ B = 0x80
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits)
+
+enum class Int16EnumWithHighBits : int16_t {
+ A = 0x2000,
+ B = 0x4000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits)
+
+enum class Uint16EnumWithHighBits : uint16_t {
+ A = 0x4000,
+ B = 0x8000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits)
+
+enum class Int32EnumWithHighBits : int32_t {
+ A = 0x20000000,
+ B = 0x40000000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits)
+
+enum class Uint32EnumWithHighBits : uint32_t {
+ A = 0x40000000u,
+ B = 0x80000000u
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits)
+
+enum class Int64EnumWithHighBits : int64_t {
+ A = 0x2000000000000000ll,
+ B = 0x4000000000000000ll
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits)
+
+enum class Uint64EnumWithHighBits : uint64_t {
+ A = 0x4000000000000000ull,
+ B = 0x8000000000000000ull
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits)
+
+// Checks that we don't accidentally truncate high bits by coercing to the wrong
+// integer type internally when implementing bitwise ops.
+template<typename EnumType, typename IntType>
+void TestIsNotTruncated()
+{
+ EnumType a = EnumType::A;
+ EnumType b = EnumType::B;
+ MOZ_RELEASE_ASSERT(IntType(a));
+ MOZ_RELEASE_ASSERT(IntType(b));
+ MOZ_RELEASE_ASSERT(a | EnumType::B);
+ MOZ_RELEASE_ASSERT(a | b);
+ MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B);
+ EnumType c = EnumType::A | EnumType::B;
+ MOZ_RELEASE_ASSERT(IntType(c));
+ MOZ_RELEASE_ASSERT(c & c);
+ MOZ_RELEASE_ASSERT(c | c);
+ MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B));
+ MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B));
+ MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B));
+ MOZ_RELEASE_ASSERT(c & EnumType::A);
+ MOZ_RELEASE_ASSERT(c & EnumType::B);
+ EnumType d = EnumType::A;
+ d |= EnumType::B;
+ MOZ_RELEASE_ASSERT(d == c);
+}
+
+int
+main()
+{
+ TestTypedEnumBasics<AutoEnum>();
+ TestTypedEnumBasics<CharEnum>();
+ TestTypedEnumBasics<Nested::AutoEnum>();
+ TestTypedEnumBasics<Nested::CharEnum>();
+
+ TestTypedEnumBitField<AutoEnumBitField>();
+ TestTypedEnumBitField<CharEnumBitField>();
+ TestTypedEnumBitField<Nested::AutoEnumBitField>();
+ TestTypedEnumBitField<Nested::CharEnumBitField>();
+
+ TestTypedEnumBitField<BitFieldFor_uint8_t>();
+ TestTypedEnumBitField<BitFieldFor_int8_t>();
+ TestTypedEnumBitField<BitFieldFor_uint16_t>();
+ TestTypedEnumBitField<BitFieldFor_int16_t>();
+ TestTypedEnumBitField<BitFieldFor_uint32_t>();
+ TestTypedEnumBitField<BitFieldFor_int32_t>();
+ TestTypedEnumBitField<BitFieldFor_uint64_t>();
+ TestTypedEnumBitField<BitFieldFor_int64_t>();
+ TestTypedEnumBitField<BitFieldFor_char>();
+ TestTypedEnumBitField<BitFieldFor_signed_char>();
+ TestTypedEnumBitField<BitFieldFor_unsigned_char>();
+ TestTypedEnumBitField<BitFieldFor_short>();
+ TestTypedEnumBitField<BitFieldFor_unsigned_short>();
+ TestTypedEnumBitField<BitFieldFor_int>();
+ TestTypedEnumBitField<BitFieldFor_unsigned_int>();
+ TestTypedEnumBitField<BitFieldFor_long>();
+ TestTypedEnumBitField<BitFieldFor_unsigned_long>();
+ TestTypedEnumBitField<BitFieldFor_long_long>();
+ TestTypedEnumBitField<BitFieldFor_unsigned_long_long>();
+
+ TestNoConversionsBetweenUnrelatedTypes();
+
+ TestIsNotTruncated<Int8EnumWithHighBits, int8_t>();
+ TestIsNotTruncated<Int16EnumWithHighBits, int16_t>();
+ TestIsNotTruncated<Int32EnumWithHighBits, int32_t>();
+ TestIsNotTruncated<Int64EnumWithHighBits, int64_t>();
+ TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>();
+ TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>();
+ TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>();
+ TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>();
+
+ return 0;
+}