WIP: Better CMake support; Catch unit test support

This commit is contained in:
Robert Dailey 2016-07-09 18:13:19 -05:00
parent 345a39030f
commit c535106980
7 changed files with 707 additions and 298 deletions

View File

@ -1,34 +1,211 @@
language: cpp language: cpp
env: matrix:
- COMPILER="clang++-3.7" include:
- COMPILER="g++-5" ########################################
- COMPILER="g++-4.6" ## GCC 4.4
- COMPILER="g++-4.7" ########################################
- COMPILER="g++-4.4" - os: linux
- COMPILER="g++-4.8" compiler: gcc
- COMPILER="g++-4.9" addons:
- COMPILER="g++-4.5" apt:
- COMPILER="clang++-3.3" sources:
- COMPILER="clang++-3.4" - ubuntu-toolchain-r-test
- COMPILER="clang++-3.5" packages:
- COMPILER="clang++-3.6" - g++-4.4
env:
- C_COMPILER=gcc-4.4
- CXX_COMPILER=g++-4.4
########################################
## GCC 4.5
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.5
env:
- C_COMPILER=gcc-4.5
- CXX_COMPILER=g++-4.5
########################################
## GCC 4.6
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.6
env:
- C_COMPILER=gcc-4.6
- CXX_COMPILER=g++-4.6
########################################
## GCC 4.7
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.7
env:
- C_COMPILER=gcc-4.7
- CXX_COMPILER=g++-4.7
########################################
## GCC 4.8
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
env:
- C_COMPILER=gcc-4.8
- CXX_COMPILER=g++-4.8
########################################
## GCC 4.9
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
env:
- C_COMPILER=gcc-4.9
- CXX_COMPILER=g++-4.9
########################################
## GCC 5
########################################
- os: linux
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env:
- C_COMPILER=gcc-5
- CXX_COMPILER=g++-5
########################################
## CLANG 3.3
########################################
- os: linux
compiler: clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.3
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.3 main'
key_url: 'http://llvm.org/apt/llvm-snapshot.gpg.key'
packages:
- clang-3.3
env:
- C_COMPILER=clang-3.3
- CXX_COMPILER=clang++-3.3
########################################
## CLANG 3.4
########################################
- os: linux
compiler: clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.4
packages:
- clang-3.4
env:
- C_COMPILER=clang-3.4
- CXX_COMPILER=clang++-3.4
########################################
## CLANG 3.5
########################################
- os: linux
compiler: clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
packages:
- clang-3.5
env:
- C_COMPILER=clang-3.5
- CXX_COMPILER=clang++-3.5
########################################
## CLANG 4.6
########################################
- os: linux
compiler: clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
packages:
- clang-3.6
env:
- C_COMPILER=clang-3.6
- CXX_COMPILER=clang++-3.6
########################################
## CLANG 3.7
########################################
- os: linux
compiler: clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- clang-3.7
env:
- C_COMPILER=clang-3.7
- CXX_COMPILER=clang++-3.7
git:
submodules: false
before_install:
- git submodule update --init --recursive
before_script: before_script:
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq
- sudo add-apt-repository --yes ppa:h-rayflood/llvm - sudo apt-get install ninja-build
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.5 main' - curl -O https://cmake.org/files/v3.6/cmake-3.6.0-Linux-x86_64.tar.gz
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.6 main' - tar -xzf cmake-3.6.0-Linux-x86_64.tar.gz
- sudo add-apt-repository -y 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.7 main' - sudo cp -fR cmake-3.6.0-Linux-x86_64/* /usr
- sudo apt-get update -qq
- sudo apt-get install --allow-unauthenticated $COMPILER
- git clone https://github.com/CxxTest/cxxtest.git cxxtest-ro
- curl -O https://cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz
- tar -xzf cmake-3.2.3-Linux-x86_64.tar.gz
- sudo cp -fR cmake-3.2.3-Linux-x86_64/* /usr
script: script:
- export PATH="$PATH:$(pwd)/cxxtest-ro/bin" - mkdir build
- ln -s cxxtest-ro/cxxtest cxxtest - cd build
- cd test - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$C_COMPILER -DCMAKE_CXX_COMPILER=$CXX_COMPILER
- make COMPILER=$COMPILER unix - ninja
- ctest -T test --output-on-failure

103
CMakeLists.txt Normal file
View File

@ -0,0 +1,103 @@
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
set(project_name better-enums)
project(${project_name})
include(CTest)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
# Set this to the current published version of Better Enums
set(upstream_version 0.11.2)
set(public_header_files
enum.h
)
# Directories for installed targets
set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
set(INCLUDE_DIR include/${project_name}-${upstream_version})
set(CONFIG_DIR lib/cmake/${project_name}-${upstream_version})
# Convert source files to absolute path, since `target_sources()` does not
# function well on relative paths and actually requires them to be absolute.
#
# If better enums ever gets actual translation units, we can build a STATIC
# or SHARED library, at which time this manual relative->absolute conversion
# will no longer be necessary since it won't be an INTERFACE target.
foreach(source_file ${public_header_files})
get_filename_component(abs_source_file ${source_file} ABSOLUTE)
# Use BUILD_INTERFACE because we don't actually want the interface
# source files to be exported with targets for installation purposes.
# The interface sources are only useful for our own targets, so that
# we see the files in the actual exe/lib projects for devleopment
# purposes.
#
# External projects that import better-enums do so only for the
# public include directories and the header files we use should not
# be put into their own projects.
list(APPEND absolute_source_files
$<BUILD_INTERFACE:${abs_source_file}>
)
endforeach()
###################################################################
## DEFINE BUILD TARGETS
###################################################################
# Main Library Target
add_library(${project_name} INTERFACE)
target_sources(${project_name} INTERFACE ${absolute_source_files})
# Test Targets
if(BUILD_TESTING)
add_subdirectory(test)
endif()
###################################################################
## INSTALL TARGETS & FILES
###################################################################
# Install all of our public header files
install(FILES
${public_header_files}
DESTINATION ${INCLUDE_DIR}
)
# Generate export rules for better-enums target
install(TARGETS ${project_name} EXPORT ${project_name}-targets
INCLUDES DESTINATION ${INCLUDE_DIR}
)
install(EXPORT ${project_name}-targets
DESTINATION ${CONFIG_DIR}
)
include(CMakePackageConfigHelpers)
# Generate the Config Package file. Used by find_package() in
# downstream projects to find the better enums library
configure_package_config_file(
${project_name}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${project_name}-config.cmake
INSTALL_DESTINATION ${CONFIG_DIR}
PATH_VARS INSTALL_DIR INCLUDE_DIR CONFIG_DIR
)
# Version file for the config package also used by find_package() to
# allow a specific version of better enums to be found and used
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${project_name}-config-version.cmake
VERSION ${upstream_version}
COMPATIBILITY AnyNewerVersion
)
# Install the config package & version config files
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${project_name}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${project_name}-config-version.cmake
DESTINATION ${CONFIG_DIR}
)

3
CTestConfig.cmake Normal file
View File

@ -0,0 +1,3 @@
# This file is required to remain in the top-level directory of the project
# so CMake can find it. This file is deliberately blank to force CTest to
# ignore any default dart configuration settings (since we don't use dart).

View File

@ -0,0 +1,7 @@
@PACKAGE_INIT@
set(BETTER_ENUMS_DIR "@PACKAGE_INSTALL_DIR@")
set(BETTER_ENUMS_INCLUDE_DIR "@PACKAGE_INCLUDE_DIR@")
set(BETTER_ENUMS_CONFIG_DIR "@PACKAGE_CONFIG_DIR@")
include(${CMAKE_CURRENT_LIST_DIR}/better-enums-targets.cmake)

View File

@ -1,12 +1,80 @@
# Invoked automatically by the Makefile. # Define catch as an interface target
add_library(catch INTERFACE)
target_include_directories(catch INTERFACE catch/single_include)
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) ###################################################################################
##
###################################################################################
macro( _parse_target_args prefix )
set( OPTIONS
)
project("Better Enums Testing" CXX) set( ONE_VALUE_KEYWORDS
)
set( MULTI_VALUE_KEYWORDS
SOURCE_FILES
DEPENDENCIES
)
CMAKE_PARSE_ARGUMENTS(
${prefix}
"${OPTIONS}"
"${ONE_VALUE_KEYWORDS}"
"${MULTI_VALUE_KEYWORDS}"
${ARGN}
)
endmacro()
###################################################################################
##
###################################################################################
function(define_target target_name target_type)
_parse_target_args(DT ${ARGN})
if(NOT DT_SOURCE_FILES)
message(SEND_ERROR "Target ${target_name} defined with no source files")
endif()
if(target_type STREQUAL "EXECUTABLE")
add_executable(${target_name} ${DT_SOURCE_FILES})
else()
# @todo Add support for shared & static libraries later, if needed
message(FATAL_ERROR "Unknown target type specified: ${target_type}")
endif()
if(DT_DEPENDENCIES)
target_link_libraries(${target_name} ${DT_DEPENDENCIES})
endif()
endfunction()
###################################################################################
##
###################################################################################
function(define_test test_name)
set(test_files ${ARGN})
define_target(${test_name} EXECUTABLE
SOURCE_FILES ${test_files}
DEPENDENCIES catch ${project_name}
)
add_test(NAME ${test_name} COMMAND ${test_name})
endfunction()
###################################################################################
##
###################################################################################
function(define_multiple_tests)
foreach(test_file ${ARGN})
get_filename_component(filename ${test_file} NAME_WE)
#string( REPLACE "test_" "" filename ${filename} )
define_test(${filename} ${test_file})
endforeach()
endfunction()
# Detect compiler feature support. # Detect compiler feature support
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_constexpr CONSTEXPR_INDEX) list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_constexpr CONSTEXPR_INDEX)
if(CONSTEXPR_INDEX EQUAL -1) if(CONSTEXPR_INDEX EQUAL -1)
set(SUPPORTS_CONSTEXPR 0) set(SUPPORTS_CONSTEXPR 0)
@ -102,102 +170,8 @@ else()
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
endif() endif()
set(test_files
source/test_enum.cpp
)
# Basic tests. define_multiple_tests(${test_files})
add_executable(cxxtest cxxtest/tests.cc)
add_executable(linking linking/helper.cc linking/main.cc)
set(PERFORMANCE_TESTS
1-simple 2-include_empty 3-only_include_enum 4-declare_enums 5-iostream)
foreach(TEST ${PERFORMANCE_TESTS})
add_executable(performance-${TEST} performance/${TEST}.cc)
endforeach(TEST)
# Select examples to build.
set(EXAMPLES
1-hello-world 2-conversions 3-iterate 4-switch 6-iostreams 7-safety
8-representation 9-constexpr 101-special-values 103-bitset 104-quine
105-c++17-reflection)
set(SKIPPED_FOR_CXX98
5-map 9-constexpr 101-special-values 103-bitset 104-quine
105-c++17-reflection)
set(SKIPPED_FOR_STRICT_CONVERSION 4-switch)
if(CONFIGURATION STREQUAL CXX98 OR NOT SUPPORTS_CONSTEXPR)
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_CXX98})
endif()
if(CONFIGURATION STREQUAL STRICT_CONVERSION)
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_STRICT_CONVERSION})
endif()
if(CONFIGURATION STREQUAL CXX14)
set(EXAMPLES 5-map)
endif()
foreach(EXAMPLE ${EXAMPLES})
add_executable(example-${EXAMPLE} ../example/${EXAMPLE}.cc)
endforeach(EXAMPLE)
# Add compiler flags.
include_directories(..)
include_directories(../extra)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
include(CheckCXXCompilerFlag)
macro(add_cxx_flag_if_supported FLAG)
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
if(HAVE_FLAG_${FLAG})
add_definitions(${FLAG})
endif()
endmacro()
macro(add_cxx_flag_to_target_if_supported TARGET FLAG)
string(REPLACE "=" "_equals_" ESCAPED ${FLAG})
string(REPLACE "+" "_plus_" ESCAPED ${ESCAPED})
check_cxx_compiler_flag("${FLAG}" HAVE_FLAG_${FLAG})
if(HAVE_FLAG_${FLAG})
get_target_property(FLAGS ${TARGET} COMPILE_FLAGS)
if(${FLAGS} STREQUAL "FLAGS-NOTFOUND")
set(FLAGS "")
endif()
set_target_properties(
${TARGET} PROPERTIES COMPILE_FLAGS "${FLAGS} ${FLAG}")
endif()
endmacro()
add_cxx_flag_if_supported("-Wpedantic")
add_cxx_flag_if_supported("-Wall")
add_cxx_flag_if_supported("-Wextra")
add_cxx_flag_if_supported("-Wno-variadic-macros")
add_cxx_flag_if_supported("-Wno-unused-const-variable")
add_cxx_flag_to_target_if_supported(linking "-Weverything")
add_cxx_flag_to_target_if_supported(linking "-Wno-c++98-compat-pedantic")
add_cxx_flag_to_target_if_supported(linking "-Wno-padded")
add_cxx_flag_to_target_if_supported(linking "-Wno-global-constructors")
add_cxx_flag_to_target_if_supported(linking "-Wno-old-style-cast")
add_cxx_flag_to_target_if_supported(linking "-Wno-missing-prototypes")
add_cxx_flag_to_target_if_supported(linking "-Wshadow")
add_cxx_flag_to_target_if_supported(linking "-Weffc++")
add_cxx_flag_to_target_if_supported(linking "-Wstrict-aliasing")
add_cxx_flag_to_target_if_supported(linking "-Wformat")
add_cxx_flag_to_target_if_supported(linking "-Wmissing-include-dirs")
add_cxx_flag_to_target_if_supported(linking "-Wsync-nand")
add_cxx_flag_to_target_if_supported(linking "-Wconditionally-supported")
add_cxx_flag_to_target_if_supported(linking "-Wconversion")
add_cxx_flag_to_target_if_supported(linking "-Wuseless-cast")
add_definitions("-Werror")
endif()

View File

@ -1,167 +0,0 @@
# Run "make" for quick builds while developing.
# Run "make default-all" before submitting a pull request.
# Run "make clean" to clean up.
# See doc/CONTRIBUTING.md for full instructions.
CXXTEST_GENERATED := cxxtest/tests.cc
UNIX_MAKE_COMMAND := make
WINDOWS_MAKE_COMMAND := "MSBuild.exe \"Better Enums Testing.sln\""
UNIX_OUTPUT_DIRECTORY := .
WINDOWS_OUTPUT_DIRECTORY := Debug
ifdef COMSPEC
WIN32 := true
endif
ifdef ComSpec
WIN32 := true
endif
ifndef WIN32
DEFAULT_MAKE_COMMAND := $(UNIX_MAKE_COMMAND)
DEFAULT_OUTPUT_DIRECTORY := $(UNIX_OUTPUT_DIRECTORY)
define PATH_FIX
@true
endef
SUFFIX :=
CXXTESTGEN := cxxtestgen
else
DEFAULT_MAKE_COMMAND := $(WINDOWS_MAKE_COMMAND)
DEFAULT_OUTPUT_DIRECTORY := $(WINDOWS_OUTPUT_DIRECTORY)
define PATH_FIX
sed 's!include "/!include "C:/cygwin/!g' $1 > $$$$ && mv $$$$ $1
endef
SUFFIX := .exe
CXXTESTGEN := python `which cxxtestgen | sed -E 's!(/cygdrive)?/c/!c:/!'`
endif
DEFAULTS := \
TITLE=default \
MAKE_COMMAND=$(DEFAULT_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(DEFAULT_OUTPUT_DIRECTORY)
# Builds one configuration with the system compiler. This will be either a
# regular C++11 or C++98 build (no constexpr to_string and no strict
# conversions).
.PHONY : default
default : examples
make $(DEFAULTS) one-configuration
# Builds all configurations with the system compiler.
.PHONY : default-all
default-all : examples
make $(DEFAULTS) all-configurations
.PHONY : examples
examples :
make -C ../doc examples
# Example: make COMPILER=clang++36 unix
.PHONY : unix
unix :
make TITLE=$(COMPILER) CMAKE_OPTIONS="-DCMAKE_CXX_COMPILER=$(COMPILER)" \
MAKE_COMMAND=$(UNIX_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(UNIX_OUTPUT_DIRECTORY) all-configurations
# Example: make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
.PHONY : ms
ms :
make TITLE=$(TITLE) CMAKE_OPTIONS="-G \\\"$(COMPILER)\\\"" \
MAKE_COMMAND=$(WINDOWS_MAKE_COMMAND) \
OUTPUT_DIRECTORY=$(WINDOWS_OUTPUT_DIRECTORY) all-configurations
# Expects three variables to be defined:
# CMAKE_OPTIONS:
# First, the compiler:
# - Empty for a "default" build.
# - -G "Visual Studio XX YYYY" to select a specific Microsoft compiler.
# - -DCMAKE_CXX_COMPILER=AAA to select a specific Unix compiler binary.
# Configuration selection (e.g. -DCONFIGURATION=CXX98) also go here.
# TITLE:
# The build title (subdirectory). Some combination of compiler/configuration.
# MAKE_COMMAND:
# Either make or msbuild "Better Enums Testing.sln"
# OUTPUT_DIRECTORY:
# Path to generated binaries relative to build directory. Either "." or
# "Debug".
.PHONY : one-configuration
one-configuration : $(CXXTEST_GENERATED)
mkdir -p build/$(TITLE)
cd build/$(TITLE) && cmake $(CMAKE_OPTIONS) ../.. && $(MAKE_COMMAND)
rm -rf build/$(TITLE)/bin
[ -f build/$(TITLE)/do-not-test ] || \
( ln -s $(OUTPUT_DIRECTORY) build/$(TITLE)/bin && \
make BIN=build/$(TITLE)/bin run-tests )
.PHONY : run-tests
run-tests :
$(BIN)/cxxtest
@for FILE in $(BIN)/example-*$(SUFFIX) ; \
do \
EXAMPLE=$$(basename $$FILE | sed s/\.exe$$// | sed s/^example-//) ; \
$$FILE | sed 's/\r$$//' | cmp - expect/$$EXAMPLE ; \
RESULT=$$? ; \
if [ $$RESULT -ne 0 ] ; \
then \
echo \'$$FILE\' produced bad output ; \
exit $$RESULT ; \
fi ; \
done
@echo Example program output matches expected output
.PHONY : all-configurations
all-configurations :
make TITLE=$(TITLE)-c++11 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-full-constexpr \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=FULL_CONSTEXPR" \
one-configuration
make TITLE=$(TITLE)-enum-class \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=STRICT_CONVERSION" \
one-configuration
make TITLE=$(TITLE)-c++14 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX14" \
one-configuration
make TITLE=$(TITLE)-c++98 \
CMAKE_OPTIONS="$(CMAKE_OPTIONS) -DCONFIGURATION=CXX98" \
one-configuration
.PHONY : all-unix
all-unix : examples
make COMPILER=clang++39 unix
make COMPILER=clang++38 unix
make COMPILER=clang++37 unix
make COMPILER=g++52 unix
make COMPILER=g++46 unix
make COMPILER=g++47 unix
make COMPILER=g++43 unix
make COMPILER=g++48 unix
make COMPILER=g++49 unix
make COMPILER=g++44 unix
make COMPILER=g++45 unix
make COMPILER=clang++33 unix
make COMPILER=clang++34 unix
make COMPILER=clang++35 unix
make COMPILER=clang++36 unix
.PHONY : all-ms
all-ms : examples
make TITLE=vc2015 COMPILER="Visual Studio 14 2015" ms
make TITLE=vc2008 COMPILER="Visual Studio 9 2008" ms
make TITLE=vc2010 COMPILER="Visual Studio 10 2010" ms
make TITLE=vc2012 COMPILER="Visual Studio 11 2012" ms
make TITLE=vc2013 COMPILER="Visual Studio 12 2013" ms
$(CXXTEST_GENERATED) : cxxtest/*.h
$(CXXTESTGEN) --error-printer -o $@ $^
$(call PATH_FIX,$@)
.PHONY : clean
clean :
rm -rf build $(CXXTEST_GENERATED)

312
test/source/test_enum.cpp Normal file
View File

@ -0,0 +1,312 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <type_traits>
#include <enum.h>
#define MAIN_TAG "[better-enums]"
BETTER_ENUM(Channel, short, Red, Green, Blue)
BETTER_ENUM(Depth, short, HighColor = 40, TrueColor = 20)
BETTER_ENUM(Compression, short, None, Huffman, Default = Huffman)
namespace test
{
BETTER_ENUM(Namespaced, short, One, Two)
}
// Using BETTER_ENUMS_HAVE_CONSTEXPR_ as a proxy for C++11 support. This should
// be changed to be more precise in the future.
#ifdef BETTER_ENUMS_HAVE_CONSTEXPR_
// 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>()));
// Temporarily disabled due to outdated libraries in Travis.
// static_assert_1((std::is_same<
// short, std::underlying_type<Channel::_enumerated>::type>()));
static_assert_1(!(std::is_same<int, Channel::_integral>()));
// Temporarily disabled due to outdated libraries in Travis.
// 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.
// Apparently, this isn't supported by Clang in Travis.
// #ifdef __clang__
// static_assert_1(std::is_trivially_copyable<Channel>());
// #endif
static_assert_1((std::is_constructible<Channel, Channel::_enumerated>()));
// "Passes" by causing a compilation error.
// static_assert_1(!(std::is_constructible<Channel, Channel::_integral>()));
// "Passes" on most compilers, passes on g++47 by causing a compilation error.
// 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);
namespace name_clash_test
{
struct Foo {};
std::ostream& operator<<(std::ostream&, Foo);
BETTER_ENUM(Enum, int, ONE, TWO, THREE)
static_assert_1((std::is_same<decltype(std::declval<std::ostream&>() << +Enum::ONE), std::ostream&>()));
}
#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
TEST_CASE("test constant values", MAIN_TAG)
{
CHECK((+Channel::Red)._to_integral() == 0);
CHECK((+Channel::Green)._to_integral() == 1);
CHECK((+Channel::Blue)._to_integral() == 2);
CHECK((+Depth::HighColor)._to_integral() == 40);
CHECK((+Depth::TrueColor)._to_integral() == 20);
}
TEST_CASE("test integral conversions", MAIN_TAG)
{
CHECK(Channel::_from_integral(1) == +Channel::Green);
CHECK(Channel::_from_integral(1) != +Channel::Blue);
CHECK(Channel::_from_integral_unchecked(1) == +Channel::Green);
CHECK(Channel::_from_integral_unchecked(1) != +Channel::Blue);
CHECK_THROWS_AS(Channel::_from_integral(3), std::runtime_error);
CHECK_NOTHROW(Channel::_from_integral_unchecked(3));
better_enums::optional<Channel> maybe_channel =
Channel::_from_integral_nothrow(2);
CHECK(maybe_channel);
CHECK(*maybe_channel == +Channel::Blue);
CHECK(!Channel::_from_integral_nothrow(3));
CHECK(Channel::_is_valid((Channel::_integral)0));
CHECK(Channel::_is_valid(1));
CHECK(Channel::_is_valid(2));
CHECK(!Channel::_is_valid(3));
}
TEST_CASE("test string conversions", MAIN_TAG)
{
CHECK(strcmp((+Channel::Green)._to_string(), "Green") == 0);
CHECK(strcmp((+Depth::HighColor)._to_string(), "HighColor") == 0);
CHECK(Channel::_from_string("Green") == +Channel::Green);
CHECK(Channel::_from_string("Green") != +Channel::Blue);
CHECK(Channel::_from_string("Blue") == +Channel::Blue);
CHECK(Channel::_from_string("Blue") != +Channel::Green);
CHECK_THROWS_AS(Channel::_from_string("green"), std::runtime_error);
better_enums::optional<Channel> maybe_channel =
Channel::_from_string_nothrow("Green");
CHECK(maybe_channel);
CHECK(*maybe_channel == +Channel::Green);
CHECK(!Channel::_from_string_nothrow("green"));
CHECK(Channel::_from_string_nocase("green") == +Channel::Green);
CHECK(Channel::_from_string_nocase("green") != +Channel::Blue);
CHECK(Channel::_from_string_nocase("blue") == +Channel::Blue);
CHECK(Channel::_from_string_nocase("blue") != +Channel::Green);
CHECK_THROWS_AS(Channel::_from_string_nocase("a"), std::runtime_error);
maybe_channel = Channel::_from_string_nocase_nothrow("green");
CHECK(maybe_channel);
CHECK(*maybe_channel == +Channel::Green);
CHECK(!Channel::_from_string_nocase_nothrow("greeen"));
CHECK(Channel::_is_valid("Green"));
CHECK(!Channel::_is_valid("green"));
CHECK(Channel::_is_valid_nocase("green"));
CHECK(!Channel::_is_valid_nocase("greeen"));
}
TEST_CASE("test value iterable", MAIN_TAG)
{
CHECK(Channel::_size() == 3);
CHECK(Depth::_size() == 2);
CHECK(Channel::_values().size() == Channel::_size());
CHECK(*Channel::_values().begin() == +Channel::Red);
CHECK(*(Channel::_values().begin() + 1) == +Channel::Green);
CHECK(*(Channel::_values().begin() + 2) == +Channel::Blue);
CHECK(Channel::_values()[1] == +Channel::Green);
CHECK(Channel::_values()[2] == +Channel::Blue);
Channel::_value_iterator value_iterator = Channel::_values().begin();
CHECK(*value_iterator == +Channel::Red);
CHECK(value_iterator != Channel::_values().end());
++value_iterator;
CHECK(*value_iterator == +Channel::Green);
CHECK(value_iterator != Channel::_values().end());
++value_iterator;
CHECK(*value_iterator == +Channel::Blue);
CHECK(value_iterator != Channel::_values().end());
++value_iterator;
CHECK(value_iterator == Channel::_values().end());
}
TEST_CASE("test name iterable", MAIN_TAG)
{
CHECK(Channel::_names().size() == Channel::_size());
CHECK(strcmp(*Channel::_names().begin(), "Red") == 0);
CHECK(strcmp(Channel::_names()[0], "Red") == 0);
CHECK(strcmp(Depth::_names()[0], "HighColor") == 0);
Channel::_name_iterator name_iterator = Channel::_names().begin();
CHECK(strcmp(*name_iterator, "Red") == 0);
CHECK(name_iterator != Channel::_names().end());
++name_iterator;
CHECK(strcmp(*name_iterator, "Green") == 0);
CHECK(name_iterator != Channel::_names().end());
++name_iterator;
CHECK(strcmp(*name_iterator, "Blue") == 0);
CHECK(name_iterator != Channel::_names().end());
++name_iterator;
CHECK(name_iterator == Channel::_names().end());
}
TEST_CASE("test type name", MAIN_TAG)
{
CHECK(strcmp(Channel::_name(), "Channel") == 0);
CHECK(strcmp(Depth::_name(), "Depth") == 0);
CHECK(strcmp(Compression::_name(), "Compression") == 0);
}
/// @todo This test case is failing and is currently deemed invalid
/// at this time.
///
/// @see https://github.com/aantron/better-enums/issues/24
/*
TEST_CASE("test alias", MAIN_TAG)
{
CHECK(Compression::Default == Compression::Huffman);
}
*/
TEST_CASE("test namespaced", MAIN_TAG)
{
CHECK((+test::Namespaced::One)._to_integral() == 0);
CHECK(test::Namespaced::_from_integral(0) == +test::Namespaced::One);
CHECK(strcmp((+test::Namespaced::One)._to_string(), "One") == 0);
CHECK(test::Namespaced::_from_string("Two") == +test::Namespaced::Two);
CHECK(test::Namespaced::_values()[0] == +test::Namespaced::One);
CHECK(strcmp(test::Namespaced::_names()[0], "One") == 0);
CHECK(*test::Namespaced::_values().begin() == +test::Namespaced::One);
CHECK(strcmp(*test::Namespaced::_names().begin(), "One") == 0);
}
BETTER_ENUM(Compiler, int, GCC, Clang, MSVC)
TEST_CASE("test stream output", MAIN_TAG)
{
std::ostringstream stream;
stream << +Compiler::GCC;
CHECK(stream.str() == "GCC");
}
TEST_CASE("test stream input", MAIN_TAG)
{
std::istringstream stream("Clang");
Compiler compiler = Compiler::GCC;
stream >> compiler;
CHECK(compiler == +Compiler::Clang);
}
BETTER_ENUM(InternalNameCollisions, int,
EnumClassForSwitchStatements, PutNamesInThisScopeAlso,
force_initialization, value_array, raw_names, name_storage,
name_array, initialized, the_raw_names, the_name_array)