From f930ce31cf11e37b37bf1b970fe326aa4fdaba24 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 7 Jun 2014 02:30:29 +0400 Subject: [PATCH] Added tests for scoped enums and underlying_type. Fixed a bug with native_value(). Fixed a bug that allowed implicit conversions of scoped enums to int (at least with clang 3.4). --- include/boost/core/scoped_enum.hpp | 3 +- test/Jamfile.v2 | 6 + test/scoped_enum.cpp | 157 ++++++++++++++++++ ...scoped_enum_compile_fail_conv_from_int.cpp | 30 ++++ test/scoped_enum_compile_fail_conv_to_int.cpp | 31 ++++ test/underlying_type.cpp | 68 ++++++++ 6 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 test/scoped_enum.cpp create mode 100644 test/scoped_enum_compile_fail_conv_from_int.cpp create mode 100644 test/scoped_enum_compile_fail_conv_to_int.cpp create mode 100644 test/underlying_type.cpp diff --git a/include/boost/core/scoped_enum.hpp b/include/boost/core/scoped_enum.hpp index 2fbdea4..78c548b 100644 --- a/include/boost/core/scoped_enum.hpp +++ b/include/boost/core/scoped_enum.hpp @@ -63,7 +63,7 @@ namespace boost inline typename EnumType::enum_type native_value(EnumType e) { - return e.native_value_(); + return e.get_native_value_(); } #else // BOOST_NO_CXX11_SCOPED_ENUMS @@ -126,7 +126,6 @@ namespace boost #define BOOST_SCOPED_ENUM_DECLARE_END2() \ enum_type get_native_value_() const BOOST_NOEXCEPT { return enum_type(v_); } \ - operator enum_type() const BOOST_NOEXCEPT { return get_native_value_(); } \ friend bool operator ==(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)==enum_type(rhs.v_); } \ friend bool operator ==(self_type lhs, enum_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)==rhs; } \ friend bool operator ==(enum_type lhs, self_type rhs) BOOST_NOEXCEPT { return lhs==enum_type(rhs.v_); } \ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 40c374e..e44688e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -75,3 +75,9 @@ run demangle_test.cpp : : : always_show_run_output ; run demangled_name_test.cpp : : : always_show_run_output ; run demangled_name_test.cpp : : : off always_show_run_output : demangled_name_test_no_rtti ; + +run scoped_enum.cpp ; +compile-fail scoped_enum_compile_fail_conv_from_int.cpp ; +compile-fail scoped_enum_compile_fail_conv_to_int.cpp ; + +run underlying_type.cpp ; diff --git a/test/scoped_enum.cpp b/test/scoped_enum.cpp new file mode 100644 index 0000000..2a83749 --- /dev/null +++ b/test/scoped_enum.cpp @@ -0,0 +1,157 @@ +/* + * Copyright Andrey Semashev 2014. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file scoped_enum.cpp + * \author Andrey Semashev + * \date 06.06.2014 + * + * \brief This test checks that scoped enum emulation works similar to C++11 scoped enums. + */ + +#include +#include + +BOOST_SCOPED_ENUM_DECLARE_BEGIN(namespace_enum1) +{ + value0, + value1, + value2 +} +BOOST_SCOPED_ENUM_DECLARE_END(namespace_enum1) + +BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(namespace_enum2, unsigned char) +{ + // Checks that enum value names do not clash + value0 = 10, + value1 = 20, + value2 = 30 +} +BOOST_SCOPED_ENUM_DECLARE_END(namespace_enum2) + +struct my_struct +{ + // Checks that declarations are valid in class scope + BOOST_SCOPED_ENUM_DECLARE_BEGIN(color) + { + red, + green, + blue + } + BOOST_SCOPED_ENUM_DECLARE_END(color) + + color m_color; + + explicit my_struct(color col) : m_color(col) + { + } + + color get_color() const + { + return m_color; + } +}; + +void check_operators() +{ + namespace_enum1 enum1 = namespace_enum1::value0; + BOOST_TEST(enum1 == namespace_enum1::value0); + BOOST_TEST(enum1 != namespace_enum1::value1); + BOOST_TEST(enum1 != namespace_enum1::value2); + + enum1 = namespace_enum1::value1; + BOOST_TEST(enum1 != namespace_enum1::value0); + BOOST_TEST(enum1 == namespace_enum1::value1); + BOOST_TEST(enum1 != namespace_enum1::value2); + + BOOST_TEST(!(enum1 < namespace_enum1::value0)); + BOOST_TEST(!(enum1 <= namespace_enum1::value0)); + BOOST_TEST(enum1 >= namespace_enum1::value0); + BOOST_TEST(enum1 > namespace_enum1::value0); + + BOOST_TEST(!(enum1 < namespace_enum1::value1)); + BOOST_TEST(enum1 <= namespace_enum1::value1); + BOOST_TEST(enum1 >= namespace_enum1::value1); + BOOST_TEST(!(enum1 > namespace_enum1::value1)); + + namespace_enum1 enum2 = namespace_enum1::value0; + BOOST_TEST(enum1 != enum2); + + enum2 = enum1; + BOOST_TEST(enum1 == enum2); +} + +void check_argument_passing() +{ + my_struct str(my_struct::color::green); + BOOST_TEST(str.get_color() == my_struct::color::green); +} + +void check_switch_case() +{ + my_struct str(my_struct::color::blue); + + switch (boost::native_value(str.get_color())) + { + case my_struct::color::blue: + break; + default: + BOOST_ERROR("Unexpected color value in switch/case"); + } +} + +template< typename T > +struct my_trait +{ + enum _ { value = 0 }; +}; + +template< > +struct my_trait< BOOST_SCOPED_ENUM_NATIVE(namespace_enum2) > +{ + enum _ { value = 1 }; +}; + +template< typename T > +void native_type_helper(T) +{ + BOOST_TEST(my_trait< T >::value != 0); +} + +void check_native_type() +{ + BOOST_TEST(my_trait< int >::value == 0); + BOOST_TEST(my_trait< BOOST_SCOPED_ENUM_NATIVE(namespace_enum2) >::value != 0); + BOOST_TEST(my_trait< boost::native_type< namespace_enum2 >::type >::value != 0); + + namespace_enum2 enum1 = namespace_enum2::value0; + native_type_helper(boost::native_value(enum1)); +} + +void check_underlying_cast() +{ + namespace_enum2 enum1 = namespace_enum2::value1; + BOOST_TEST(boost::underlying_cast< unsigned char >(enum1) == 20); +} + +void check_underlying_type() +{ + // The real check for the type is in the underlying_type trait test. + namespace_enum2 enum1 = namespace_enum2::value1; + BOOST_TEST(sizeof(enum1) == sizeof(unsigned char)); +} + +int main(int, char*[]) +{ + check_operators(); + check_argument_passing(); + check_switch_case(); + check_native_type(); + check_underlying_cast(); + check_underlying_type(); + + return boost::report_errors(); +} diff --git a/test/scoped_enum_compile_fail_conv_from_int.cpp b/test/scoped_enum_compile_fail_conv_from_int.cpp new file mode 100644 index 0000000..2ff144f --- /dev/null +++ b/test/scoped_enum_compile_fail_conv_from_int.cpp @@ -0,0 +1,30 @@ +/* + * Copyright Andrey Semashev 2014. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file scoped_enum_compile_fail_conv_from_int.cpp + * \author Andrey Semashev + * \date 06.06.2014 + * + * \brief This test checks that scoped enum emulation prohibits implicit conversions from int + */ + +#include + +BOOST_SCOPED_ENUM_DECLARE_BEGIN(color) +{ + red, + green, + blue +} +BOOST_SCOPED_ENUM_DECLARE_END(color) + +int main(int, char*[]) +{ + color col = 2; + + return boost::native_value(col); +} diff --git a/test/scoped_enum_compile_fail_conv_to_int.cpp b/test/scoped_enum_compile_fail_conv_to_int.cpp new file mode 100644 index 0000000..699e0bb --- /dev/null +++ b/test/scoped_enum_compile_fail_conv_to_int.cpp @@ -0,0 +1,31 @@ +/* + * Copyright Andrey Semashev 2014. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file scoped_enum_compile_fail_conv_to_int.cpp + * \author Andrey Semashev + * \date 06.06.2014 + * + * \brief This test checks that scoped enum emulation prohibits implicit conversions to int + */ + +#include + +BOOST_SCOPED_ENUM_DECLARE_BEGIN(color) +{ + red, + green, + blue +} +BOOST_SCOPED_ENUM_DECLARE_END(color) + +int main(int, char*[]) +{ + color col = color::red; + int n = col; + + return n; +} diff --git a/test/underlying_type.cpp b/test/underlying_type.cpp new file mode 100644 index 0000000..0823f58 --- /dev/null +++ b/test/underlying_type.cpp @@ -0,0 +1,68 @@ +/* + * Copyright Andrey Semashev 2014. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file underlying_type.cpp + * \author Andrey Semashev + * \date 06.06.2014 + * + * \brief This test checks that underlying_type trait works. + */ + +#include +#include +#include +#include +#include + +BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(emulated_enum, unsigned char) +{ + value0, + value1, + value2 +} +BOOST_SCOPED_ENUM_DECLARE_END(emulated_enum) + +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +enum class native_enum : unsigned short +{ + value0, + value1, + value2 +}; + +#endif + +#if defined(BOOST_NO_UNDERLYING_TYPE) +namespace boost { + +template< > +struct underlying_type< emulated_enum > +{ + typedef unsigned char type; +}; + +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) +template< > +struct underlying_type< native_enum > +{ + typedef unsigned short type; +}; +#endif + +} // namespace boost +#endif + +int main(int, char*[]) +{ + BOOST_TEST_TRAIT_TRUE((boost::core::is_same< boost::underlying_type< emulated_enum >::type, unsigned char >)); +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + BOOST_TEST_TRAIT_TRUE((boost::core::is_same< boost::underlying_type< native_enum >::type, unsigned short >)); +#endif + + return boost::report_errors(); +}