diff --git a/.travis.yml b/.travis.yml index aa58c5dfc..ae12dbcc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,49 +1,38 @@ language: cpp +dist: trusty +sudo: false +group: beta + +addons: + apt: + sources: + - 'ubuntu-toolchain-r-test' + - 'boost-latest' + packages: + - 'g++-multilib' + - 'libboost-serialization-dev' +# - 'libboost-test-dev' compiler: - # TODO: Clang is currently giving issues - #- clang - gcc -before_install: - # Always install g++4.8.1 - - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - - # Install recent version of Boost - - sudo add-apt-repository -y ppa:boost-latest/ppa +matrix: + include: + - os: linux + compiler: clang + env: CMAKE_OPTIONS="-DSKIP_PORTABILITY_TEST=ON" - # clang 3.3 - - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi + # TODO: Add an entry for valgrind + # after_script: make valgrind - - sudo apt-get update -qq - -install: - - sudo apt-get install cmake - - sudo apt-get install libboost1.54-all-dev - - # Always install valgrind - - sudo apt-get install valgrind - - # Always install g++4.8.1 - - sudo apt-get install -qq g++-4.8 - - sudo apt-get install -qq g++-4.8-multilib - - if [ "$CXX" = "g++" ]; then export CMAKE_CXX_COMPILER="g++-4.8"; fi - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi - - # clang 3.3 - - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.3; fi - - if [ "$CXX" == "clang++" ]; then export CMAKE_CXX_COMPILER="clang++-3.3"; fi - - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.3"; fi + - os: osx + osx_image: xcode8 + compiler: clang script: - - mkdir build - - cd build - - cmake .. - - make - -after_script: - - ctest . - # - make valgrind + - mkdir build && cd build + - cmake ${CMAKE_OPTIONS} .. && make -j4 + - ctest . --output-on-failure branches: only: diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f3f604b4..dcb9cd677 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required (VERSION 2.6.2) project (cereal) -option(SKIP_PORTABILITY_TEST "Skip portability tests" OFF) +option(SKIP_PORTABILITY_TEST "Skip portability (32 bit) tests" OFF) if(NOT CMAKE_VERSION VERSION_LESS 3.0) # installing cereal requires INTERFACE lib option(JUST_INSTALL_CEREAL "Don't do anything besides installing the library" OFF) endif() @@ -14,8 +14,14 @@ else() set(CEREAL_THREAD_LIBS "") endif() -if(NOT MSVC) - set(CMAKE_CXX_FLAGS "-Wall -Werror -g -Wextra -Wshadow -pedantic ${CMAKE_CXX_FLAGS}") +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /W3 /WX") +else() + set(CMAKE_CXX_FLAGS "-Wall -g -Wextra -Wshadow -pedantic -Wold-style-cast ${CMAKE_CXX_FLAGS}") + option(WITH_WERROR "Compile with '-Werror' C++ compiler flag" ON) + if(WITH_WERROR) + set(CMAKE_CXX_FLAGS "-Werror ${CMAKE_CXX_FLAGS}") + endif(WITH_WERROR) if(CMAKE_VERSION VERSION_LESS 3.1) set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") else() @@ -45,31 +51,16 @@ endif() include_directories(./include) -find_package(Boost COMPONENTS serialization unit_test_framework) +# Boost serialization for performance sandbox +find_package(Boost COMPONENTS serialization) if(Boost_FOUND) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) - enable_testing() - add_subdirectory(unittests) endif(Boost_FOUND) + +enable_testing() +add_subdirectory(unittests) add_subdirectory(sandbox) -find_package(Doxygen) -if(DOXYGEN_FOUND) - - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen.in" "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" @ONLY) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - COMMENT "Generating API documentation with Doxygen" VERBATIM - ) - - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scripts/updatedoc.in" "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" @ONLY) - add_custom_target(update-doc - COMMAND "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" - DEPENDS doc - COMMENT "Copying documentation to gh-pages branch" VERBATIM - ) - -endif(DOXYGEN_FOUND) +add_subdirectory(doc) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..121eba152 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,35 @@ +# can use variables like {build} and {branch} +version: 1.2.{build} +pull_requests: + do_not_increment_build_number: true + +branches: + only: + - develop + +configuration: + - Debug + - Release + +environment: + matrix: + - VS_VERSION_MAJOR: 12 + - VS_VERSION_MAJOR: 14 + BOOST_ROOT: C:\Libraries\boost_1_59_0 + +platform: + - Win32 + - x64 + +before_build: "scripts\\appveyor.bat" + +build: + parallel: true + project: build/cereal.sln + verbosity: minimal + +test_script: "scripts\\appveyor.bat test" + +artifacts: + - path: build\Testing + - path: out diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 000000000..ec0316e97 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,18 @@ +find_package(Doxygen) +if(DOXYGEN_FOUND) + + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doxygen.in" "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" @ONLY) + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.." + COMMENT "Generating API documentation with Doxygen" VERBATIM + ) + + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../scripts/updatedoc.in" "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" @ONLY) + add_custom_target(update-doc + COMMAND "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" + DEPENDS doc + COMMENT "Copying documentation to gh-pages branch" VERBATIM + ) + +endif(DOXYGEN_FOUND) \ No newline at end of file diff --git a/doc/doxygen.in b/doc/doxygen.in index 55fc748a8..ddf1398b9 100644 --- a/doc/doxygen.in +++ b/doc/doxygen.in @@ -52,7 +52,7 @@ PROJECT_LOGO = # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = doc +OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output @@ -595,7 +595,7 @@ FILE_VERSION_FILTER = # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. -LAYOUT_FILE = "@CMAKE_CURRENT_SOURCE_DIR@/doc/DoxygenLayout.xml" +LAYOUT_FILE = "@CMAKE_CURRENT_SOURCE_DIR@/DoxygenLayout.xml" # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The @@ -668,7 +668,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@/doc #include doc +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../include @CMAKE_CURRENT_SOURCE_DIR@/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -701,7 +701,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = external +EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/../external # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -911,7 +911,7 @@ HTML_HEADER = # each generated HTML page. If it is left blank doxygen will generate a # standard footer. -HTML_FOOTER ="@CMAKE_CURRENT_SOURCE_DIR@/doc/footer.html" +HTML_FOOTER ="@CMAKE_CURRENT_SOURCE_DIR@/footer.html" # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to @@ -1476,13 +1476,13 @@ XML_OUTPUT = xml # which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +# XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +# XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting @@ -1626,7 +1626,7 @@ TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = cereal.doxytags # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes diff --git a/include/cereal/access.hpp b/include/cereal/access.hpp index 407ffcc83..63c1f74af 100644 --- a/include/cereal/access.hpp +++ b/include/cereal/access.hpp @@ -34,8 +34,8 @@ #include #include -#include -#include +#include "cereal/macros.hpp" +#include "cereal/details/helpers.hpp" namespace cereal { diff --git a/include/cereal/archives/adapters.hpp b/include/cereal/archives/adapters.hpp index d9558adeb..0191e3239 100644 --- a/include/cereal/archives/adapters.hpp +++ b/include/cereal/archives/adapters.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_ #define CEREAL_ARCHIVES_ADAPTERS_HPP_ -#include +#include "cereal/details/helpers.hpp" #include namespace cereal diff --git a/include/cereal/archives/binary.hpp b/include/cereal/archives/binary.hpp index 74342b3a7..7e0032268 100644 --- a/include/cereal/archives/binary.hpp +++ b/include/cereal/archives/binary.hpp @@ -29,7 +29,7 @@ #ifndef CEREAL_ARCHIVES_BINARY_HPP_ #define CEREAL_ARCHIVES_BINARY_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/archives/json.hpp b/include/cereal/archives/json.hpp index 3eb95db5f..9d57434ab 100644 --- a/include/cereal/archives/json.hpp +++ b/include/cereal/archives/json.hpp @@ -29,8 +29,8 @@ #ifndef CEREAL_ARCHIVES_JSON_HPP_ #define CEREAL_ARCHIVES_JSON_HPP_ -#include -#include +#include "cereal/cereal.hpp" +#include "cereal/details/util.hpp" namespace cereal { @@ -50,11 +50,11 @@ namespace cereal #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag -#include -#include -#include -#include -#include +#include "cereal/external/rapidjson/prettywriter.h" +#include "cereal/external/rapidjson/ostreamwrapper.h" +#include "cereal/external/rapidjson/istreamwrapper.h" +#include "cereal/external/rapidjson/document.h" +#include "cereal/external/base64.hpp" #include #include @@ -96,8 +96,8 @@ namespace cereal { enum class NodeType { StartObject, InObject, StartArray, InArray }; - using WriteStream = rapidjson::OStreamWrapper; - using JSONWriter = rapidjson::PrettyWriter; + using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper; + using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter; public: /*! @name Common Functionality @@ -242,7 +242,7 @@ namespace cereal //! Saves a double to the current node void saveValue(double d) { itsWriter.Double(d); } //! Saves a string to the current node - void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast( s.size() )); } + void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast( s.size() )); } //! Saves a const char * to the current node void saveValue(char const * s) { itsWriter.String(s); } //! Saves a nullptr to the current node @@ -406,11 +406,11 @@ namespace cereal class JSONInputArchive : public InputArchive, public traits::TextArchive { private: - using ReadStream = rapidjson::IStreamWrapper; - typedef rapidjson::GenericValue> JSONValue; + using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper; + typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue> JSONValue; typedef JSONValue::ConstMemberIterator MemberIterator; typedef JSONValue::ConstValueIterator ValueIterator; - typedef rapidjson::Document::GenericValue GenericValue; + typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue; public: /*! @name Common Functionality @@ -471,11 +471,17 @@ namespace cereal Iterator(MemberIterator begin, MemberIterator end) : itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member) - { } + { + if( std::distance( begin, end ) == 0 ) + itsType = Null_; + } Iterator(ValueIterator begin, ValueIterator end) : itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value) - { } + { + if( std::distance( begin, end ) == 0 ) + itsType = Null_; + } //! Advance to the next node Iterator & operator++() @@ -491,7 +497,7 @@ namespace cereal { case Value : return itsValueItBegin[itsIndex]; case Member: return itsMemberItBegin[itsIndex].value; - default: throw cereal::Exception("Invalid Iterator Type!"); + default: throw cereal::Exception("JSONInputArchive internal error: null or empty iterator to object or array!"); } } @@ -528,7 +534,7 @@ namespace cereal MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object) ValueIterator itsValueItBegin, itsValueItEnd; //!< The value iterator (array) size_t itsIndex; //!< The current index of this iterator - enum Type {Value, Member, Null_} itsType; //!< Whether this holds values (array) or members (objects) or nothing + enum Type {Value, Member, Null_} itsType; //!< Whether this holds values (array) or members (objects) or nothing }; //! Searches for the expectedName node if it doesn't match the actualName @@ -713,7 +719,7 @@ namespace cereal const char * itsNextName; //!< Next name set by NVP ReadStream itsReadStream; //!< Rapidjson write stream std::vector itsIteratorStack; //!< 'Stack' of rapidJSON iterators - rapidjson::Document itsDocument; //!< Rapidjson document + CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument; //!< Rapidjson document }; // ###################################################################### diff --git a/include/cereal/archives/portable_binary.hpp b/include/cereal/archives/portable_binary.hpp index f9d72d224..76e634ba6 100644 --- a/include/cereal/archives/portable_binary.hpp +++ b/include/cereal/archives/portable_binary.hpp @@ -29,7 +29,7 @@ #ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_ #define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_ -#include +#include "cereal/cereal.hpp" #include #include diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp index 63f737acc..c520f02e2 100644 --- a/include/cereal/archives/xml.hpp +++ b/include/cereal/archives/xml.hpp @@ -28,12 +28,12 @@ */ #ifndef CEREAL_ARCHIVES_XML_HPP_ #define CEREAL_ARCHIVES_XML_HPP_ -#include -#include +#include "cereal/cereal.hpp" +#include "cereal/details/util.hpp" -#include -#include -#include +#include "cereal/external/rapidxml/rapidxml.hpp" +#include "cereal/external/rapidxml/rapidxml_print.hpp" +#include "cereal/external/base64.hpp" #include #include diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp index f6640d477..a77701037 100644 --- a/include/cereal/cereal.hpp +++ b/include/cereal/cereal.hpp @@ -39,10 +39,10 @@ #include #include -#include -#include -#include -#include +#include "cereal/macros.hpp" +#include "cereal/details/traits.hpp" +#include "cereal/details/helpers.hpp" +#include "cereal/types/base_class.hpp" namespace cereal { @@ -255,6 +255,20 @@ namespace cereal a large project from Boost to cereal. The preferred interface for cereal is using operator(). */ //! @{ + //! Indicates this archive is not intended for loading + /*! This ensures compatibility with boost archive types. If you are transitioning + from boost, you can check this value within a member or external serialize function + (i.e., Archive::is_loading::value) to disable behavior specific to loading, until + you can transition to split save/load or save_minimal/load_minimal functions */ + using is_loading = std::false_type; + + //! Indicates this archive is intended for saving + /*! This ensures compatibility with boost archive types. If you are transitioning + from boost, you can check this value within a member or external serialize function + (i.e., Archive::is_saving::value) to enable behavior specific to loading, until + you can transition to split save/load or save_minimal/load_minimal functions */ + using is_saving = std::true_type; + //! Serializes passed in data /*! This is a boost compatability layer and is not the preferred way of using cereal. If you are transitioning from boost, use this until you can @@ -611,6 +625,20 @@ namespace cereal a large project from Boost to cereal. The preferred interface for cereal is using operator(). */ //! @{ + //! Indicates this archive is intended for loading + /*! This ensures compatibility with boost archive types. If you are transitioning + from boost, you can check this value within a member or external serialize function + (i.e., Archive::is_loading::value) to enable behavior specific to loading, until + you can transition to split save/load or save_minimal/load_minimal functions */ + using is_loading = std::true_type; + + //! Indicates this archive is not intended for saving + /*! This ensures compatibility with boost archive types. If you are transitioning + from boost, you can check this value within a member or external serialize function + (i.e., Archive::is_saving::value) to disable behavior specific to loading, until + you can transition to split save/load or save_minimal/load_minimal functions */ + using is_saving = std::false_type; + //! Serializes passed in data /*! This is a boost compatability layer and is not the preferred way of using cereal. If you are transitioning from boost, use this until you can @@ -954,6 +982,6 @@ namespace cereal } // namespace cereal // This include needs to come after things such as binary_data, make_nvp, etc -#include +#include "cereal/types/common.hpp" #endif // CEREAL_CEREAL_HPP_ diff --git a/include/cereal/details/helpers.hpp b/include/cereal/details/helpers.hpp index 527c7c62b..909268809 100644 --- a/include/cereal/details/helpers.hpp +++ b/include/cereal/details/helpers.hpp @@ -37,8 +37,8 @@ #include #include -#include -#include +#include "cereal/macros.hpp" +#include "cereal/details/static_object.hpp" namespace cereal { @@ -55,8 +55,10 @@ namespace cereal //! The size type used by cereal /*! To ensure compatability between 32, 64, etc bit machines, we need to use a fixed size type instead of size_t, which may vary from machine to - machine. */ - using size_type = uint64_t; + machine. + + The default value for CEREAL_SIZE_TYPE is specified in cereal/macros.hpp */ + using size_type = CEREAL_SIZE_TYPE; // forward decls class BinaryOutputArchive; diff --git a/include/cereal/details/polymorphic_impl.hpp b/include/cereal/details/polymorphic_impl.hpp index e15075882..81128c8b1 100644 --- a/include/cereal/details/polymorphic_impl.hpp +++ b/include/cereal/details/polymorphic_impl.hpp @@ -45,13 +45,16 @@ #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ -#include -#include -#include -#include +#include "cereal/details/polymorphic_impl_fwd.hpp" +#include "cereal/details/static_object.hpp" +#include "cereal/types/memory.hpp" +#include "cereal/types/string.hpp" #include #include #include +#include +#include +#include //! Binds a polymorhic type to all registered archives /*! This binds a polymorphic type to all compatible registered archives that @@ -115,6 +118,8 @@ namespace cereal //! Maps from base type index to a map from derived type index to caster std::map>> map; + std::multimap reverseMap; + //! Error message used for unregistered polymorphic casts #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \ throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \ @@ -186,8 +191,8 @@ namespace cereal auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } ); void * uptr = dptr; - for( auto const * map : mapping ) - uptr = map->upcast( uptr ); + for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter ) + uptr = (*mIter)->upcast( uptr ); return uptr; } @@ -199,8 +204,8 @@ namespace cereal auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } ); std::shared_ptr uptr = dptr; - for( auto const * map : mapping ) - uptr = map->upcast( uptr ); + for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter ) + uptr = (*mIter)->upcast( uptr ); return uptr; } @@ -218,72 +223,143 @@ namespace cereal assuming dynamic type information is available */ PolymorphicVirtualCaster() { + const auto baseKey = std::type_index(typeid(Base)); + const auto derivedKey = std::type_index(typeid(Derived)); + + // First insert the relation Base->Derived const auto lock = StaticObject::lock(); auto & baseMap = StaticObject::getInstance().map; - auto baseKey = std::type_index(typeid(Base)); auto lb = baseMap.lower_bound(baseKey); { auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second; - auto derivedKey = std::type_index(typeid(Derived)); auto lbd = derivedMap.lower_bound(derivedKey); auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second; derivedVec.push_back( this ); } + // Insert reverse relation Derived->Base + auto & reverseMap = StaticObject::getInstance().reverseMap; + reverseMap.insert( {derivedKey, baseKey} ); + // Find all chainable unregistered relations - std::map>> unregisteredRelations; + /* The strategy here is to process only the nodes in the class hierarchy graph that have been + affected by the new insertion. The aglorithm iteratively processes a node an ensures that it + is updated with all new shortest length paths. It then rocesses the parents of the active node, + with the knowledge that all children have already been processed. + + Note that for the following, we'll use the nomenclature of parent and child to not confuse with + the inserted base derived relationship */ { - auto checkRelation = [](std::type_index const & baseInfo, std::type_index const & derivedInfo) + // Checks whether there is a path from parent->child and returns a pair + // dist is set to MAX if the path does not exist + auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) -> + std::pair> { - const bool exists = PolymorphicCasters::exists( baseInfo, derivedInfo ); - return std::make_pair( exists, exists ? PolymorphicCasters::lookup( baseInfo, derivedInfo, [](){} ) : - std::vector{} ); + if( PolymorphicCasters::exists( parentInfo, childInfo ) ) + { + auto const & path = PolymorphicCasters::lookup( parentInfo, childInfo, [](){} ); + return {path.size(), path}; + } + else + return {std::numeric_limits::max(), {}}; }; - for( auto baseIt : baseMap ) - for( auto derivedIt : baseIt.second ) + std::stack parentStack; // Holds the parent nodes to be processed + std::set dirtySet; // Marks child nodes that have been changed + std::set processedParents; // Marks parent nodes that have been processed + + // Begin processing the base key and mark derived as dirty + parentStack.push( baseKey ); + dirtySet.insert( derivedKey ); + + while( !parentStack.empty() ) + { + using Relations = std::multimap>>; + Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation + + const auto parent = parentStack.top(); + parentStack.pop(); + + // Update paths to all children marked dirty + for( auto const & childPair : baseMap[parent] ) { - for( auto otherBaseIt : baseMap ) + const auto child = childPair.first; + if( dirtySet.count( child ) && baseMap.count( child ) ) { - if( baseIt.first == otherBaseIt.first ) // only interested in chained relations - continue; + auto parentChildPath = checkRelation( parent, child ); - // Check if there exists a mapping otherBase -> base -> derived that is shorter than - // any existing otherBase -> derived direct mapping - auto otherBaseItToDerived = checkRelation( otherBaseIt.first, derivedIt.first ); - auto baseToDerived = checkRelation( baseIt.first, derivedIt.first ); - auto otherBaseToBase = checkRelation( otherBaseIt.first, baseIt.first ); + // Search all paths from the child to its own children (finalChild), + // looking for a shorter parth from parent to finalChild + for( auto const & finalChildPair : baseMap[child] ) + { + const auto finalChild = finalChildPair.first; + + auto parentFinalChildPath = checkRelation( parent, finalChild ); + auto childFinalChildPath = checkRelation( child, finalChild ); + + const size_t newLength = 1u + parentChildPath.first; + + if( newLength < parentFinalChildPath.first ) + { + std::vector path = parentChildPath.second; + path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() ); + + // Check to see if we have a previous uncommitted path in unregisteredRelations + // that is shorter. If so, ignore this path + auto hintRange = unregisteredRelations.equal_range( parent ); + auto hint = hintRange.first; + for( ; hint != hintRange.second; ++hint ) + if( hint->second.first == finalChild ) + break; + + const bool uncommittedExists = hint != unregisteredRelations.end(); + if( uncommittedExists && (hint->second.second.size() <= newLength) ) + continue; + + auto newPath = std::pair>{finalChild, std::move(path)}; + + // Insert the new path if it doesn't exist, otherwise this will just lookup where to do the + // replacement + #ifdef CEREAL_OLDER_GCC + auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) ); + #else // NOT CEREAL_OLDER_GCC + auto old = unregisteredRelations.emplace_hint( hint, parent, newPath ); + #endif // NOT CEREAL_OLDER_GCC + + // If there was an uncommitted path, we need to perform a replacement + if( uncommittedExists ) + old->second = newPath; + } + } // end loop over child's children + } // end if dirty and child has children + } // end loop over children + + // Insert chained relations + for( auto const & it : unregisteredRelations ) + { + auto & derivedMap = baseMap.find( it.first )->second; + derivedMap[it.second.first] = it.second.second; + reverseMap.insert( {it.second.first, it.first} ); + } - const size_t newLength = otherBaseToBase.second.size() + baseToDerived.second.size(); - const bool isShorterOrFirstPath = !otherBaseItToDerived.first || (newLength < derivedIt.second.size()); + // Mark current parent as modified + dirtySet.insert( parent ); - if( isShorterOrFirstPath && - baseToDerived.first && - otherBaseToBase.first ) - { - std::vector path = otherBaseToBase.second; - path.insert( path.end(), baseToDerived.second.begin(), baseToDerived.second.end() ); - - #ifdef CEREAL_OLDER_GCC - unregisteredRelations.insert( std::make_pair(otherBaseIt.first, - std::pair>{derivedIt.first, std::move(path)}) ); - #else // NOT CEREAL_OLDER_GCC - unregisteredRelations.emplace( otherBaseIt.first, - std::pair>{derivedIt.first, std::move(path)} ); - #endif // NOT CEREAL_OLDER_GCC - } - } // end otherBaseIt - } // end derivedIt - } // end chain lookup - - // Insert chained relations - for( auto it : unregisteredRelations ) - { - auto & derivedMap = baseMap.find( it.first )->second; - derivedMap[it.second.first] = it.second.second; - } - } + // Insert all parents of the current parent node that haven't yet been processed + auto parentRange = reverseMap.equal_range( parent ); + for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter ) + { + const auto pParent = pIter->second; + if( !processedParents.count( pParent ) ) + { + parentStack.push( pParent ); + processedParents.insert( pParent ); + } + } + } // end loop over parent stack + } // end chainable relations + } // end PolymorphicVirtualCaster() //! Performs the proper downcast with the templated types void const * downcast( void const * const ptr ) const override @@ -644,8 +720,8 @@ namespace cereal { //! Binding for non abstract types void bind(std::false_type) const - { - instantiate_polymorphic_binding((T*) 0, 0, Tag{}, adl_tag{}); + { + instantiate_polymorphic_binding(static_cast(nullptr), 0, Tag{}, adl_tag{}); } //! Binding for abstract types diff --git a/include/cereal/details/static_object.hpp b/include/cereal/details/static_object.hpp index 6afdb75d1..c9c888d7d 100644 --- a/include/cereal/details/static_object.hpp +++ b/include/cereal/details/static_object.hpp @@ -28,7 +28,7 @@ #ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_ #define CEREAL_DETAILS_STATIC_OBJECT_HPP_ -#include +#include "cereal/macros.hpp" #if CEREAL_THREAD_SAFE #include @@ -109,6 +109,7 @@ namespace cereal static LockGuard lock() { #if CEREAL_THREAD_SAFE + static std::mutex instanceMutex; return LockGuard{instanceMutex}; #else return LockGuard{}; @@ -117,15 +118,9 @@ namespace cereal private: static T & instance; - #if CEREAL_THREAD_SAFE - static std::mutex instanceMutex; - #endif }; template T & StaticObject::instance = StaticObject::create(); - #if CEREAL_THREAD_SAFE - template std::mutex StaticObject::instanceMutex; - #endif } // namespace detail } // namespace cereal diff --git a/include/cereal/details/traits.hpp b/include/cereal/details/traits.hpp index f7e301cc8..3390bbd31 100644 --- a/include/cereal/details/traits.hpp +++ b/include/cereal/details/traits.hpp @@ -39,8 +39,8 @@ #include #include -#include -#include +#include "cereal/macros.hpp" +#include "cereal/access.hpp" namespace cereal { @@ -1180,9 +1180,9 @@ namespace cereal struct shared_from_this_wrapper { template - static auto check( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() ); + static auto (check)( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() ); - static auto check( ... ) -> decltype( std::false_type() ); + static auto (check)( ... ) -> decltype( std::false_type() ); template static auto get( U const & t ) -> decltype( t.shared_from_this() ); @@ -1191,7 +1191,7 @@ namespace cereal //! Determine if T or any base class of T has inherited from std::enable_shared_from_this template - struct has_shared_from_this : decltype(detail::shared_from_this_wrapper::check(std::declval())) + struct has_shared_from_this : decltype((detail::shared_from_this_wrapper::check)(std::declval())) { }; //! Get the type of the base class of T which inherited from std::enable_shared_from_this diff --git a/include/cereal/external/base64.hpp b/include/cereal/external/base64.hpp index 32e17cf8d..7eee0037b 100644 --- a/include/cereal/external/base64.hpp +++ b/include/cereal/external/base64.hpp @@ -50,10 +50,10 @@ namespace cereal while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { - char_array_4[0] = (unsigned char) ((char_array_3[0] & 0xfc) >> 2); - char_array_4[1] = (unsigned char) ( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) ); - char_array_4[2] = (unsigned char) ( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) ); - char_array_4[3] = (unsigned char) ( char_array_3[2] & 0x3f ); + char_array_4[0] = static_cast((char_array_3[0] & 0xfc) >> 2); + char_array_4[1] = static_cast( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) ); + char_array_4[2] = static_cast( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) ); + char_array_4[3] = static_cast( char_array_3[2] & 0x3f ); for(i = 0; (i <4) ; i++) ret += chars[char_array_4[i]]; @@ -76,11 +76,9 @@ namespace cereal while((i++ < 3)) ret += '='; - } return ret; - } inline std::string decode(std::string const& encoded_string) { @@ -95,7 +93,7 @@ namespace cereal char_array_4[i++] = encoded_string[in_]; in_++; if (i ==4) { for (i = 0; i <4; i++) - char_array_4[i] = (unsigned char) chars.find( char_array_4[i] ); + char_array_4[i] = static_cast(chars.find( char_array_4[i] )); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); @@ -112,7 +110,7 @@ namespace cereal char_array_4[j] = 0; for (j = 0; j <4; j++) - char_array_4[j] = (unsigned char) chars.find( char_array_4[j] ); + char_array_4[j] = static_cast(chars.find( char_array_4[j] )); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); diff --git a/include/cereal/macros.hpp b/include/cereal/macros.hpp index eb2a05b9a..cfdc14c59 100644 --- a/include/cereal/macros.hpp +++ b/include/cereal/macros.hpp @@ -56,6 +56,20 @@ #define CEREAL_THREAD_SAFE 0 #endif // CEREAL_THREAD_SAFE +#ifndef CEREAL_SIZE_TYPE +//! Determines the data type used for size_type +/*! cereal uses size_type to ensure that the serialized size of + dynamic containers is compatible across different architectures + (e.g. 32 vs 64 bit), which may use different underlying types for + std::size_t. + + More information can be found in cereal/details/helpers.hpp. + + If you choose to modify this type, ensure that you use a fixed + size type (e.g. uint32_t). */ +#define CEREAL_SIZE_TYPE uint64_t +#endif // CEREAL_SIZE_TYPE + // ###################################################################### #ifndef CEREAL_SERIALIZE_FUNCTION_NAME //! The serialization/deserialization function name to search for. diff --git a/include/cereal/types/array.hpp b/include/cereal/types/array.hpp index 34766e9af..f5d510abf 100644 --- a/include/cereal/types/array.hpp +++ b/include/cereal/types/array.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_ARRAY_HPP_ #define CEREAL_TYPES_ARRAY_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/base_class.hpp b/include/cereal/types/base_class.hpp index 10441ab95..37b551ede 100644 --- a/include/cereal/types/base_class.hpp +++ b/include/cereal/types/base_class.hpp @@ -30,8 +30,8 @@ #ifndef CEREAL_TYPES_BASE_CLASS_HPP_ #define CEREAL_TYPES_BASE_CLASS_HPP_ -#include -#include +#include "cereal/details/traits.hpp" +#include "cereal/details/polymorphic_impl_fwd.hpp" namespace cereal { diff --git a/include/cereal/types/bitset.hpp b/include/cereal/types/bitset.hpp index fe389a8af..12d3a8276 100644 --- a/include/cereal/types/bitset.hpp +++ b/include/cereal/types/bitset.hpp @@ -30,8 +30,8 @@ #ifndef CEREAL_TYPES_BITSET_HPP_ #define CEREAL_TYPES_BITSET_HPP_ -#include -#include +#include "cereal/cereal.hpp" +#include "cereal/types/string.hpp" #include namespace cereal @@ -148,6 +148,8 @@ namespace cereal std::uint8_t chunk = 0; std::uint8_t mask = 0; + bits.reset(); + // Load one chunk at a time, rotating through the chunk // to set bits in the bitset for( std::size_t i = 0; i < N; ++i ) diff --git a/include/cereal/types/boost_variant.hpp b/include/cereal/types/boost_variant.hpp index f74123828..e1863c14f 100644 --- a/include/cereal/types/boost_variant.hpp +++ b/include/cereal/types/boost_variant.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_ #define CEREAL_TYPES_BOOST_VARIANT_HPP_ -#include +#include "cereal/cereal.hpp" #include #include diff --git a/include/cereal/types/common.hpp b/include/cereal/types/common.hpp index 57ab204b1..b239daa76 100644 --- a/include/cereal/types/common.hpp +++ b/include/cereal/types/common.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_COMMON_HPP_ #define CEREAL_TYPES_COMMON_HPP_ -#include +#include "cereal/cereal.hpp" namespace cereal { diff --git a/include/cereal/types/concepts/pair_associative_container.hpp b/include/cereal/types/concepts/pair_associative_container.hpp index 9936e5bc0..5f0fd746c 100644 --- a/include/cereal/types/concepts/pair_associative_container.hpp +++ b/include/cereal/types/concepts/pair_associative_container.hpp @@ -31,7 +31,7 @@ #ifndef CEREAL_CONCEPTS_PAIR_ASSOCIATIVE_CONTAINER_HPP_ #define CEREAL_CONCEPTS_PAIR_ASSOCIATIVE_CONTAINER_HPP_ -#include +#include "cereal/cereal.hpp" namespace cereal { diff --git a/include/cereal/types/deque.hpp b/include/cereal/types/deque.hpp index df93e64d4..0491d28d0 100644 --- a/include/cereal/types/deque.hpp +++ b/include/cereal/types/deque.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_DEQUE_HPP_ #define CEREAL_TYPES_DEQUE_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/forward_list.hpp b/include/cereal/types/forward_list.hpp index 72a8b8822..db87e1f5c 100644 --- a/include/cereal/types/forward_list.hpp +++ b/include/cereal/types/forward_list.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_FORWARD_LIST_HPP_ #define CEREAL_TYPES_FORWARD_LIST_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/list.hpp b/include/cereal/types/list.hpp index d071e72f8..6008204ff 100644 --- a/include/cereal/types/list.hpp +++ b/include/cereal/types/list.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_LIST_HPP_ #define CEREAL_TYPES_LIST_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/map.hpp b/include/cereal/types/map.hpp index 3ed99581e..41845e980 100644 --- a/include/cereal/types/map.hpp +++ b/include/cereal/types/map.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_MAP_HPP_ #define CEREAL_TYPES_MAP_HPP_ -#include +#include "cereal/types/concepts/pair_associative_container.hpp" #include #endif // CEREAL_TYPES_MAP_HPP_ diff --git a/include/cereal/types/memory.hpp b/include/cereal/types/memory.hpp index 6b0324085..40c965a6c 100644 --- a/include/cereal/types/memory.hpp +++ b/include/cereal/types/memory.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_SHARED_PTR_HPP_ #define CEREAL_TYPES_SHARED_PTR_HPP_ -#include +#include "cereal/cereal.hpp" #include #include @@ -419,7 +419,7 @@ namespace cereal } // namespace cereal // automatically include polymorphic support -#include +#include "cereal/types/polymorphic.hpp" #undef CEREAL_ALIGNOF #endif // CEREAL_TYPES_SHARED_PTR_HPP_ \ No newline at end of file diff --git a/include/cereal/types/polymorphic.hpp b/include/cereal/types/polymorphic.hpp index a7754ca81..5acc11f8a 100644 --- a/include/cereal/types/polymorphic.hpp +++ b/include/cereal/types/polymorphic.hpp @@ -30,13 +30,13 @@ #ifndef CEREAL_TYPES_POLYMORPHIC_HPP_ #define CEREAL_TYPES_POLYMORPHIC_HPP_ -#include -#include +#include "cereal/cereal.hpp" +#include "cereal/types/memory.hpp" -#include -#include -#include -#include +#include "cereal/details/util.hpp" +#include "cereal/details/helpers.hpp" +#include "cereal/details/traits.hpp" +#include "cereal/details/polymorphic_impl.hpp" #ifdef _MSC_VER #define CEREAL_STATIC_CONSTEXPR static diff --git a/include/cereal/types/queue.hpp b/include/cereal/types/queue.hpp index c0e41a201..52d26a2f0 100644 --- a/include/cereal/types/queue.hpp +++ b/include/cereal/types/queue.hpp @@ -30,13 +30,13 @@ #ifndef CEREAL_TYPES_QUEUE_HPP_ #define CEREAL_TYPES_QUEUE_HPP_ -#include +#include "cereal/details/helpers.hpp" #include // The default container for queue is deque, so let's include that too -#include +#include "cereal/types/deque.hpp" // The default comparator for queue is less -#include +#include "cereal/types/functional.hpp" namespace cereal { diff --git a/include/cereal/types/set.hpp b/include/cereal/types/set.hpp index a5b3bc6ae..149a5b45a 100644 --- a/include/cereal/types/set.hpp +++ b/include/cereal/types/set.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_SET_HPP_ #define CEREAL_TYPES_SET_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/stack.hpp b/include/cereal/types/stack.hpp index d2a666760..b69b66000 100644 --- a/include/cereal/types/stack.hpp +++ b/include/cereal/types/stack.hpp @@ -30,11 +30,11 @@ #ifndef CEREAL_TYPES_STACK_HPP_ #define CEREAL_TYPES_STACK_HPP_ -#include +#include "cereal/cereal.hpp" #include // The default container for stack is deque, so let's include that too -#include +#include "cereal/types/deque.hpp" namespace cereal { diff --git a/include/cereal/types/string.hpp b/include/cereal/types/string.hpp index 55ebe722a..e7488a9c2 100644 --- a/include/cereal/types/string.hpp +++ b/include/cereal/types/string.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_STRING_HPP_ #define CEREAL_TYPES_STRING_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/tuple.hpp b/include/cereal/types/tuple.hpp index 2831728ae..7e56f0dc1 100644 --- a/include/cereal/types/tuple.hpp +++ b/include/cereal/types/tuple.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_TUPLE_HPP_ #define CEREAL_TYPES_TUPLE_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/unordered_map.hpp b/include/cereal/types/unordered_map.hpp index 68ee9c4a8..3b0f80ba4 100644 --- a/include/cereal/types/unordered_map.hpp +++ b/include/cereal/types/unordered_map.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_UNORDERED_MAP_HPP_ #define CEREAL_TYPES_UNORDERED_MAP_HPP_ -#include +#include "cereal/types/concepts/pair_associative_container.hpp" #include #endif // CEREAL_TYPES_UNORDERED_MAP_HPP_ diff --git a/include/cereal/types/unordered_set.hpp b/include/cereal/types/unordered_set.hpp index f3cdebda8..b86d8e5c1 100644 --- a/include/cereal/types/unordered_set.hpp +++ b/include/cereal/types/unordered_set.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_UNORDERED_SET_HPP_ #define CEREAL_TYPES_UNORDERED_SET_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/utility.hpp b/include/cereal/types/utility.hpp index 1dc382dc5..076bea893 100644 --- a/include/cereal/types/utility.hpp +++ b/include/cereal/types/utility.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_UTILITY_HPP_ #define CEREAL_TYPES_UTILITY_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/valarray.hpp b/include/cereal/types/valarray.hpp index eade2fe3b..dcc471d77 100644 --- a/include/cereal/types/valarray.hpp +++ b/include/cereal/types/valarray.hpp @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef CEREAL_TYPES_VALARRAY_HPP_ #define CEREAL_TYPES_VALARRAY_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/include/cereal/types/vector.hpp b/include/cereal/types/vector.hpp index 36a2a4ccf..8302cb900 100644 --- a/include/cereal/types/vector.hpp +++ b/include/cereal/types/vector.hpp @@ -30,7 +30,7 @@ #ifndef CEREAL_TYPES_VECTOR_HPP_ #define CEREAL_TYPES_VECTOR_HPP_ -#include +#include "cereal/cereal.hpp" #include namespace cereal diff --git a/sandbox/CMakeLists.txt b/sandbox/CMakeLists.txt index 5008e420f..52c8df890 100644 --- a/sandbox/CMakeLists.txt +++ b/sandbox/CMakeLists.txt @@ -10,5 +10,8 @@ include_directories(sandbox_shared_lib) if(Boost_FOUND) add_executable(performance performance.cpp) + if(MSVC) + set_target_properties(performance PROPERTIES COMPILE_DEFINITIONS "BOOST_SERIALIZATION_DYN_LINK") + endif() target_link_libraries(performance ${Boost_LIBRARIES}) endif(Boost_FOUND) diff --git a/sandbox/sandbox.cpp b/sandbox/sandbox.cpp index b1ca28420..af28b22c6 100644 --- a/sandbox/sandbox.cpp +++ b/sandbox/sandbox.cpp @@ -651,9 +651,9 @@ int main() iar( d1 ); assert( d1->x == 4 && d1->y == 3 ); iar( d2 ); - assert( ((Derived*)d2.get())->x == 5 && ((Derived*)d2.get())->y == 4 ); + assert( dynamic_cast(d2.get())->x == 5 && dynamic_cast(d2.get())->y == 4 ); iar( d3 ); - assert( ((Derived*)d3.get())->x == 6 && ((Derived*)d3.get())->y == 5 ); + assert( dynamic_cast(d3.get())->x == 6 && dynamic_cast(d3.get())->y == 5 ); } { diff --git a/sandbox/sandbox_json.cpp b/sandbox/sandbox_json.cpp index 83abb8d2f..e767ca590 100644 --- a/sandbox/sandbox_json.cpp +++ b/sandbox/sandbox_json.cpp @@ -311,31 +311,6 @@ struct OOJson } }; -enum Bla -{ - x, - y -}; - -template -void save( Archive & ar, Bla const & b ) -{ - ar( (const int &)b ); -} - -template -void load( Archive & ar, Bla & b ) -{ - ar( (int&)b ); -} - -CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Bla, cereal::specialization::non_member_load_save ) - -//namespace cereal -//{ -// //template struct specialize {}; -//} - // ###################################################################### int main() { @@ -370,8 +345,6 @@ int main() auto f2 = f; archive( f ); archive( f2 ); - - archive( Bla::x ); } // test out of order diff --git a/scripts/appveyor.bat b/scripts/appveyor.bat new file mode 100644 index 000000000..5e478dece --- /dev/null +++ b/scripts/appveyor.bat @@ -0,0 +1,75 @@ +@echo off +setlocal enabledelayedexpansion + +if not defined APPVEYOR ( + @echo This script is meant to be used with AppVeyor CI. This can be used as reference. + @echo I sincerely recommend not using it for building/testing cereal locally. + exit /b 0 +) + +if not defined BOOST_ROOT ( + set BOOST_ROOT=C:\Libraries\boost +) +if not defined VS_VERSION_MAJOR ( + set VS_VERSION_MAJOR=14 +) +if not defined VS_VERSION_YEAR ( + if "%VS_VERSION_MAJOR%" == "12" ( + set VS_VERSION_YEAR=2013 + ) else if "%VS_VERSION_MAJOR%" == "14" ( + set VS_VERSION_YEAR=2015 + ) else ( + @echo Cannot use Visual Studio version %VS_VERSION_MAJOR% + exit /b 1 + ) +) +if not defined CMAKE_GENERATOR_PREFIX ( + set CMAKE_GENERATOR_PREFIX=Visual Studio %VS_VERSION_MAJOR% %VS_VERSION_YEAR% +) + +@rem CONFIGURATION is (one of the entries) defined in appveyor.yml +if not defined CONFIGURATION ( + set CONFIGURATION=Release +) +@rem PLATFORM is (one of the entries) defined in appveyor.yml +if "%PLATFORM%"=="x64" ( + set BIT_COUNT=64 + set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_PREFIX% Win64 +) else ( + set BIT_COUNT=32 + set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_PREFIX% +) + +set BOOST_LIBRARYDIR=%BOOST_ROOT%\lib%BIT_COUNT%-msvc-%VS_VERSION_MAJOR%.0 + +set START_DIR=%CD% + +if not exist build\NUL mkdir build +cd build + +if "%~1" == "test" ( + @rem overloading the batch script; Run tests if the first argument is `test` (without quotes). + @rem Cereal uses Boost Unit test framework. Rather than modifying the code to load boost test + @rem dll from its location OR copying the boost dlls to the directory of every test being run, + @rem we use another option Windows leaves us - modify the PATH. + for %%i in (ctest.exe) do set CTEST_EXE=%%~$PATH:i + PATH %BOOST_LIBRARYDIR% + "!CTEST_EXE!" -C %CONFIGURATION% + if %errorlevel% neq 0 exit /b %errorlevel% + goto done +) + +if "%PLATFORM%" == "x64" ( + @rem please excuse the hack - CMake is unable to produce multiarch MSVC projects + cmake -G "%CMAKE_GENERATOR_PREFIX%" -DBOOST_ROOT=%BOOST_ROOT% -DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% .. + cmake --build . --config %CONFIGURATION% --target portability_test32 + del CMakeCache.txt + rmdir /s /q CMakeFiles +) + +cmake -G "%CMAKE_GENERATOR_NAME%" -DBOOST_ROOT=%BOOST_ROOT% -DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% .. +@rem left the actual build for later - AppVeyor enables parallel jobs in a much cleaner way than msbuild + +:done +@REM go back home +cd %START_DIR% diff --git a/scripts/updatedoc.in b/scripts/updatedoc.in index 5e7a71462..7f6a4a66d 100755 --- a/scripts/updatedoc.in +++ b/scripts/updatedoc.in @@ -8,18 +8,18 @@ set -e tempdir=`mktemp -d` branch=`git rev-parse --abbrev-ref HEAD` -cp -r @CMAKE_CURRENT_BINARY_DIR@/doc/html/ ${tempdir} +cp -r @PROJECT_BINARY_DIR@/doc/html/ ${tempdir} git stash git checkout gh-pages-develop -rm -rf @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen -mkdir @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen -cp -r ${tempdir}/html/* @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen/ +rm -rf @PROJECT_SOURCE_DIR@/assets/doxygen +mkdir @PROJECT_SOURCE_DIR@/assets/doxygen +cp -r ${tempdir}/html/* @PROJECT_SOURCE_DIR@/assets/doxygen/ rm -rf ${tempdir} -git commit @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen +git commit @PROJECT_SOURCE_DIR@/assets/doxygen git checkout ${branch} git stash apply diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index ae221d038..b7a769be4 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,21 +1,35 @@ file(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) -# A semi-colon separated list of test sources that should not be automatically built with boost unit test +# A semi-colon separated list of test sources that should not be automatically built with doctest set(SPECIAL_TESTS "portability_test.cpp") -# Build the portability test only if we are on a 64-bit machine (void* is 8 bytes) -if((${CMAKE_SIZEOF_VOID_P} EQUAL 8) AND (NOT SKIP_PORTABILITY_TEST)) - add_executable(portability_test32 portability_test.cpp) - set_target_properties(portability_test32 PROPERTIES COMPILE_FLAGS "-m32") - set_target_properties(portability_test32 PROPERTIES LINK_FLAGS "-m32") +if(CMAKE_VERSION VERSION_LESS 2.8) + # Portability test uses the `TARGET_FILE_DIR` generator expression which is available from CMake 2.8. + set(SKIP_PORTABILITY_TEST ON) +endif() + +if(NOT SKIP_PORTABILITY_TEST) + # Build the portability test only if we are on a 64-bit machine (void* is 8 bytes) + if((${CMAKE_SIZEOF_VOID_P} EQUAL 8)) + if(NOT MSVC) + add_executable(portability_test32 portability_test.cpp) + set_target_properties(portability_test32 PROPERTIES COMPILE_FLAGS "-m32") + set_target_properties(portability_test32 PROPERTIES LINK_FLAGS "-m32") + endif() - add_executable(portability_test64 portability_test.cpp) + add_executable(portability_test64 portability_test.cpp) - add_test(NAME portability_test COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/run_portability_test.sh") + add_test(NAME portability_test + COMMAND ${CMAKE_COMMAND} + -DPORTABILITY_TEST_DIR=$ + -P "${CMAKE_CURRENT_SOURCE_DIR}/run_portability_test.cmake") + elseif(MSVC) + add_executable(portability_test32 portability_test.cpp) + endif() endif() -# Build all of the non-special tests and link against the boost unit test framework +# Build all of the non-special tests foreach(TEST_SOURCE ${TESTS}) string(REPLACE ".cpp" "" TEST_TARGET "${TEST_SOURCE}") @@ -27,56 +41,51 @@ foreach(TEST_SOURCE ${TESTS}) if(IS_SPECIAL_TEST EQUAL -1) add_executable(${TEST_TARGET} ${TEST_SOURCE}) - set_target_properties(${TEST_TARGET} PROPERTIES COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${TEST_TARGET}") - target_link_libraries(${TEST_TARGET} ${Boost_LIBRARIES}) target_link_libraries(${TEST_TARGET} ${CEREAL_THREAD_LIBS}) add_test("${TEST_TARGET}" "${TEST_TARGET}") - # TODO: This won't work right now, because we would need a 32-bit boost - ## If we are on a 64-bit machine, create an extra 32-bit version of the test - #if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) - # add_executable(${TEST_TARGET}_32 ${TEST_SOURCE}) - # set_target_properties(${TEST_TARGET}_32 PROPERTIES - # COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${TEST_TARGET}" - # COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") - # target_link_libraries(${TEST_TARGET}_32 ${Boost_LIBRARIES}) - # add_test("${TEST_TARGET}_32" "${TEST_TARGET}_32") - #endif() + # If we are on a 64-bit machine, create an extra 32-bit version of the test if portability testing is enabled + if((NOT MSVC) AND (${CMAKE_SIZEOF_VOID_P} EQUAL 8) AND (NOT SKIP_PORTABILITY_TEST)) + add_executable(${TEST_TARGET}_32 ${TEST_SOURCE}) + set_target_properties(${TEST_TARGET}_32 PROPERTIES + COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") + add_test("${TEST_TARGET}_32" "${TEST_TARGET}_32") + endif() endif() endforeach() # Add the valgrind target -add_custom_target(valgrind - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/run_valgrind.sh") - -# Add the coverage target -add_custom_target(coverage) -add_custom_command(TARGET coverage - COMMAND "${CMAKE_SOURCE_DIR}/scripts/updatecoverage.sh" ${CMAKE_SOURCE_DIR} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/coverage") - -# add tests to coverage -foreach(TEST_SOURCE ${TESTS}) - string(REPLACE ".cpp" "" COVERAGE_TARGET "${TEST_SOURCE}") - set(COVERAGE_TARGET "coverage_${COVERAGE_TARGET}") - - # Check to see if our target is listed in "SPECIAL_TESTS" - list(FIND SPECIAL_TESTS "${TEST_SOURCE}" IS_SPECIAL_TEST) - - if(IS_SPECIAL_TEST EQUAL -1) - add_dependencies(coverage ${COVERAGE_TARGET}) - - add_executable(${COVERAGE_TARGET} EXCLUDE_FROM_ALL ${TEST_SOURCE}) - set_target_properties(${COVERAGE_TARGET} PROPERTIES COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${COVERAGE_TARGET}") - set_target_properties(${COVERAGE_TARGET} PROPERTIES COMPILE_FLAGS "-coverage") - set_target_properties(${COVERAGE_TARGET} PROPERTIES LINK_FLAGS "-coverage") - set_target_properties(${COVERAGE_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/coverage") - target_link_libraries(${COVERAGE_TARGET} ${Boost_LIBRARIES}) - target_link_libraries(${COVERAGE_TARGET} ${CEREAL_THREAD_LIBS}) - endif() -endforeach() +if(NOT MSVC) + add_custom_target(valgrind + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/run_valgrind.sh") + + # Add the coverage target + add_custom_target(coverage) + add_custom_command(TARGET coverage + COMMAND "${CMAKE_SOURCE_DIR}/scripts/updatecoverage.sh" ${CMAKE_SOURCE_DIR} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/coverage") + + # add tests to coverage + foreach(TEST_SOURCE ${TESTS}) + string(REPLACE ".cpp" "" COVERAGE_TARGET "${TEST_SOURCE}") + set(COVERAGE_TARGET "coverage_${COVERAGE_TARGET}") + + # Check to see if our target is listed in "SPECIAL_TESTS" + list(FIND SPECIAL_TESTS "${TEST_SOURCE}" IS_SPECIAL_TEST) + + if(IS_SPECIAL_TEST EQUAL -1) + add_dependencies(coverage ${COVERAGE_TARGET}) + + add_executable(${COVERAGE_TARGET} EXCLUDE_FROM_ALL ${TEST_SOURCE}) + set_target_properties(${COVERAGE_TARGET} PROPERTIES COMPILE_FLAGS "-coverage") + set_target_properties(${COVERAGE_TARGET} PROPERTIES LINK_FLAGS "-coverage") + set_target_properties(${COVERAGE_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/coverage") + target_link_libraries(${COVERAGE_TARGET} ${CEREAL_THREAD_LIBS}) + endif() + endforeach() +endif(NOT MSVC) if(NOT CMAKE_VERSION VERSION_LESS 3.0) add_test(test_cmake_config_module ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake-config-module.cmake) diff --git a/unittests/array.cpp b/unittests/array.cpp index 2ae3fcc80..5cd1c392a 100644 --- a/unittests/array.cpp +++ b/unittests/array.cpp @@ -24,90 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "array.hpp" -template -void test_array() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::array o_podarray; - for(auto & elem : o_podarray) - elem = random_value(gen); - - std::array o_iserarray; - for(auto & elem : o_iserarray) - elem = StructInternalSerialize( random_value(gen), random_value(gen) ); - - std::array o_isplarray; - for(auto & elem : o_isplarray) - elem = StructInternalSplit( random_value(gen), random_value(gen) ); - - std::array o_eserarray; - for(auto & elem : o_eserarray) - elem = StructExternalSerialize( random_value(gen), random_value(gen) ); - - std::array o_esplarray; - for(auto & elem : o_esplarray) - elem = StructExternalSplit( random_value(gen), random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podarray); - oar(o_iserarray); - oar(o_isplarray); - oar(o_eserarray); - oar(o_esplarray); - } - - std::array i_podarray; - std::array i_iserarray; - std::array i_isplarray; - std::array i_eserarray; - std::array i_esplarray; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podarray); - iar(i_iserarray); - iar(i_isplarray); - iar(i_eserarray); - iar(i_esplarray); - } - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podarray.begin(), i_podarray.end(), o_podarray.begin(), o_podarray.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserarray.begin(), i_iserarray.end(), o_iserarray.begin(), o_iserarray.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplarray.begin(), i_isplarray.end(), o_isplarray.begin(), o_isplarray.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserarray.begin(), i_eserarray.end(), o_eserarray.begin(), o_eserarray.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplarray.begin(), i_esplarray.end(), o_esplarray.begin(), o_esplarray.end()); - } -} +TEST_SUITE("array"); -BOOST_AUTO_TEST_CASE( binary_array ) +TEST_CASE("binary_array") { test_array(); } -BOOST_AUTO_TEST_CASE( portable_binary_array ) +TEST_CASE("portable_binary_array") { test_array(); } -BOOST_AUTO_TEST_CASE( xml_array ) +TEST_CASE("xml_array") { test_array(); } -BOOST_AUTO_TEST_CASE( json_array ) +TEST_CASE("json_array") { test_array(); } +TEST_SUITE_END(); diff --git a/unittests/array.hpp b/unittests/array.hpp new file mode 100644 index 000000000..766225b21 --- /dev/null +++ b/unittests/array.hpp @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_ARRAY_H_ +#define CEREAL_TEST_ARRAY_H_ +#include "common.hpp" + +template inline +void test_array() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::array o_podarray; + for(auto & elem : o_podarray) + elem = random_value(gen); + + std::array o_iserarray; + for(auto & elem : o_iserarray) + elem = StructInternalSerialize( random_value(gen), random_value(gen) ); + + std::array o_isplarray; + for(auto & elem : o_isplarray) + elem = StructInternalSplit( random_value(gen), random_value(gen) ); + + std::array o_eserarray; + for(auto & elem : o_eserarray) + elem = StructExternalSerialize( random_value(gen), random_value(gen) ); + + std::array o_esplarray; + for(auto & elem : o_esplarray) + elem = StructExternalSplit( random_value(gen), random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podarray); + oar(o_iserarray); + oar(o_isplarray); + oar(o_eserarray); + oar(o_esplarray); + } + + std::array i_podarray; + std::array i_iserarray; + std::array i_isplarray; + std::array i_eserarray; + std::array i_esplarray; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podarray); + iar(i_iserarray); + iar(i_isplarray); + iar(i_eserarray); + iar(i_esplarray); + } + + check_collection( i_podarray, o_podarray ); + check_collection( i_iserarray, o_iserarray ); + check_collection( i_isplarray, o_isplarray ); + check_collection( i_eserarray, o_eserarray ); + check_collection( i_esplarray, o_esplarray ); + } +} + +#endif // CEREAL_TEST_ARRAY_H_ diff --git a/unittests/basic_string.cpp b/unittests/basic_string.cpp index 65cfffb0f..245530e19 100644 --- a/unittests/basic_string.cpp +++ b/unittests/basic_string.cpp @@ -24,109 +24,27 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "basic_string.hpp" -template -void test_string_basic() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(size_t i=0; i<100; ++i) - { - std::basic_string o_string = random_basic_string(gen); - std::basic_string o_string2 = ""; - std::basic_string o_string3; - - std::ostringstream os; - { - OArchive oar(os); - oar(o_string); - oar(o_string2); - oar(o_string3); - } - - std::basic_string i_string; - std::basic_string i_string2; - std::basic_string i_string3; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_string); - iar(i_string2); - iar(i_string3); - } - - BOOST_CHECK_EQUAL(i_string, o_string); - BOOST_CHECK_EQUAL(i_string2, o_string2); - BOOST_CHECK_EQUAL(i_string3, o_string3); - } -} +TEST_SUITE("basic_string"); -template -void test_string_all() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(size_t i=0; i<100; ++i) - { - std::basic_string o_string = random_basic_string(gen); - std::basic_string o_wstring = random_basic_string(gen); - std::basic_string o_u16string = random_basic_string(gen); - std::basic_string o_u32string = random_basic_string(gen); - - std::ostringstream os; - { - OArchive oar(os); - oar(o_string); - oar(o_wstring); - oar(o_u16string); - oar(o_u32string); - } - - std::basic_string i_string; - std::basic_string i_wstring; - std::basic_string i_u16string; - std::basic_string i_u32string; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_string); - iar(i_wstring); - iar(i_u16string); - iar(i_u32string); - } - - BOOST_CHECK_EQUAL(i_string, o_string); - BOOST_CHECK_EQUAL_COLLECTIONS(i_wstring.begin(), i_wstring.end(), o_wstring.begin(), o_wstring.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_u16string.begin(), i_u16string.end(), o_u16string.begin(), o_u16string.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_u32string.begin(), i_u32string.end(), o_u32string.begin(), o_u32string.end()); - } -} - -BOOST_AUTO_TEST_CASE( binary_string ) +TEST_CASE("binary_string") { test_string_all(); } -BOOST_AUTO_TEST_CASE( portable_binary_string ) +TEST_CASE("portable_binary_string") { test_string_all(); } -BOOST_AUTO_TEST_CASE( xml_string_basic ) +TEST_CASE("xml_string_basic") { test_string_basic(); } -BOOST_AUTO_TEST_CASE( json_string_basic ) +TEST_CASE("json_string_basic") { test_string_basic(); } @@ -148,23 +66,10 @@ void test_ws_in_out(Out const & o_value_with_ws) iar(i_value_with_ws); } - BOOST_CHECK_EQUAL(i_value_with_ws, o_value_with_ws); + CHECK(i_value_with_ws == o_value_with_ws); } -namespace boost -{ - void save( cereal::XMLOutputArchive & ar, boost::string_ref const & str ) - { - ar.saveValue( str ); - } - - bool operator==( std::string const & s1, boost::string_ref const & s2 ) - { - return s1 == std::string(s2.data(), s2.length()); - } -} - -BOOST_AUTO_TEST_CASE( xml_string_issue109 ) +TEST_CASE("xml_string_issue109") { char strings[][20] = { "some text", @@ -185,16 +90,9 @@ BOOST_AUTO_TEST_CASE( xml_string_issue109 ) test_ws_in_out( o_string ); } - - for( size_t i=0; i<( sizeof( strings ) / sizeof( strings[0] ) ); ++i ) - { - boost::string_ref o_string = strings[i]; - - test_ws_in_out( o_string ); - } } -BOOST_AUTO_TEST_CASE( xml_char_issue109 ) +TEST_CASE("xml_char_issue109") { uint8_t chars[] = { ' ', @@ -251,11 +149,11 @@ void test_ws_in_out_array(Out const (&o_a_value_with_ws)[Nb]) for (size_t uiIndex = 0; uiIndex < Nb; ++uiIndex) { - BOOST_CHECK_EQUAL(i_a_value_with_ws[uiIndex], o_a_value_with_ws[uiIndex]); + CHECK(i_a_value_with_ws[uiIndex] == o_a_value_with_ws[uiIndex]); } } -BOOST_AUTO_TEST_CASE(xml_string_issue_consecutive_calls) +TEST_CASE("xml_string_issue_consecutive_calls") { std::string strings[] = { "some text", @@ -269,3 +167,5 @@ BOOST_AUTO_TEST_CASE(xml_string_issue_consecutive_calls) test_ws_in_out_array(strings); } + +TEST_SUITE_END(); diff --git a/unittests/basic_string.hpp b/unittests/basic_string.hpp new file mode 100644 index 000000000..5ee37aac1 --- /dev/null +++ b/unittests/basic_string.hpp @@ -0,0 +1,114 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_BASIC_STRING_H_ +#define CEREAL_TEST_BASIC_STRING_H_ +#include "common.hpp" + +template inline +void test_string_basic() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(size_t i=0; i<100; ++i) + { + std::basic_string o_string = random_basic_string(gen); + std::basic_string o_string2 = ""; + std::basic_string o_string3; + + std::ostringstream os; + { + OArchive oar(os); + oar(o_string); + oar(o_string2); + oar(o_string3); + } + + std::basic_string i_string; + std::basic_string i_string2; + std::basic_string i_string3; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_string); + iar(i_string2); + iar(i_string3); + } + + CHECK_EQ(i_string, o_string); + CHECK_EQ(i_string2, o_string2); + CHECK_EQ(i_string3, o_string3); + } +} + +template inline +void test_string_all() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(size_t i=0; i<100; ++i) + { + std::basic_string o_string = random_basic_string(gen); + std::basic_string o_wstring = random_basic_string(gen); + std::basic_string o_u16string = random_basic_string(gen); + std::basic_string o_u32string = random_basic_string(gen); + + std::ostringstream os; + { + OArchive oar(os); + oar(o_string); + oar(o_wstring); + oar(o_u16string); + oar(o_u32string); + } + + std::basic_string i_string; + std::basic_string i_wstring; + std::basic_string i_u16string; + std::basic_string i_u32string; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_string); + iar(i_wstring); + iar(i_u16string); + iar(i_u32string); + } + + CHECK_EQ(i_string, o_string); + check_collection( i_wstring, o_wstring ); + check_collection( i_u16string, o_u16string ); + check_collection( i_u32string, o_u32string ); + } +} + +#endif // CEREAL_TEST_BASIC_STRING_H_ diff --git a/unittests/bitset.cpp b/unittests/bitset.cpp index d882fdb71..912c22c99 100644 --- a/unittests/bitset.cpp +++ b/unittests/bitset.cpp @@ -24,77 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "bitset.hpp" -template -void test_bitset() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rng32 = [&](){ return random_binary_string<32>( gen ); }; - auto rng65 = [&](){ return random_binary_string<65>( gen ); }; - auto rng256 = [&](){ return random_binary_string<256>( gen ); }; - auto rng512 = [&](){ return random_binary_string<512>( gen ); }; - - for(int ii=0; ii<100; ++ii) - { - std::bitset<32> o_bit32( rng32() ); - std::bitset<65> o_bit65( rng65() ); - std::bitset<256> o_bit256( rng256() ); - std::bitset<512> o_bit512( rng512() ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_bit32); - oar(o_bit65); - oar(o_bit256); - oar(o_bit512); - } - - std::bitset<32> i_bit32; - std::bitset<65> i_bit65; - std::bitset<256> i_bit256; - std::bitset<512> i_bit512; +TEST_SUITE("bitset"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_bit32); - iar(i_bit65); - iar(i_bit256); - iar(i_bit512); - } - - BOOST_CHECK_EQUAL( o_bit32, i_bit32 ); - BOOST_CHECK_EQUAL( o_bit65, i_bit65 ); - BOOST_CHECK_EQUAL( o_bit256, i_bit256 ); - BOOST_CHECK_EQUAL( o_bit512, i_bit512 ); - } -} - -BOOST_AUTO_TEST_CASE( binary_bitset ) +TEST_CASE("binary_bitset") { test_bitset(); } -BOOST_AUTO_TEST_CASE( portable_binary_bitset ) +TEST_CASE("portable_binary_bitset") { test_bitset(); } -BOOST_AUTO_TEST_CASE( xml_bitset ) +TEST_CASE("xml_bitset") { test_bitset(); } -BOOST_AUTO_TEST_CASE( json_bitset ) +TEST_CASE("json_bitset") { test_bitset(); } - +TEST_SUITE_END(); diff --git a/unittests/bitset.hpp b/unittests/bitset.hpp new file mode 100644 index 000000000..09f597cf3 --- /dev/null +++ b/unittests/bitset.hpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_BITSET_H_ +#define CEREAL_TEST_BITSET_H_ +#include "common.hpp" + +template inline +void test_bitset() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rng32 = [&](){ return random_binary_string<32>( gen ); }; + auto rng65 = [&](){ return random_binary_string<65>( gen ); }; + auto rng256 = [&](){ return random_binary_string<256>( gen ); }; + auto rng512 = [&](){ return random_binary_string<512>( gen ); }; + + for(int ii=0; ii<100; ++ii) + { + std::bitset<32> o_bit32( rng32() ); + std::bitset<65> o_bit65( rng65() ); + std::bitset<256> o_bit256( rng256() ); + std::bitset<512> o_bit512( rng512() ); + std::bitset<32> o_bit32_low( 0 ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_bit32); + oar(o_bit65); + oar(o_bit256); + oar(o_bit512); + oar(o_bit32_low); + } + + std::bitset<32> i_bit32; + std::bitset<65> i_bit65; + std::bitset<256> i_bit256; + std::bitset<512> i_bit512; + std::bitset<32> i_bit32_low( 0xffffffff ); + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_bit32); + iar(i_bit65); + iar(i_bit256); + iar(i_bit512); + iar(i_bit32_low); + } + + CHECK_EQ( o_bit32, i_bit32 ); + CHECK_EQ( o_bit65, i_bit65 ); + CHECK_EQ( o_bit256, i_bit256 ); + CHECK_EQ( o_bit512, i_bit512 ); + + CHECK_EQ( o_bit32_low, i_bit32_low ); + } +} + +#endif // CEREAL_TEST_BITSET_H_ diff --git a/unittests/boost_variant.cpp b/unittests/boost_variant.cpp index 3bb9d75f2..7e073b8f4 100644 --- a/unittests/boost_variant.cpp +++ b/unittests/boost_variant.cpp @@ -24,64 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "boost_variant.hpp" -template -void test_boost_variant() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - boost::variant o_bv1 = random_value(gen); - boost::variant o_bv2 = random_value(gen); - boost::variant o_bv3 = random_basic_string(gen); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_bv1); - oar(o_bv2); - oar(o_bv3); - } - - decltype(o_bv1) i_bv1; - decltype(o_bv2) i_bv2; - decltype(o_bv3) i_bv3; +TEST_SUITE("boost_variant"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_bv1); - iar(i_bv2); - iar(i_bv3); - } - - BOOST_CHECK_EQUAL( boost::get(i_bv1), boost::get(o_bv1) ); - BOOST_CHECK_CLOSE( boost::get(i_bv2), boost::get(o_bv2), 1e-5 ); - BOOST_CHECK_EQUAL( boost::get(i_bv3), boost::get(o_bv3) ); -} - -BOOST_AUTO_TEST_CASE( binary_boost_variant ) +TEST_CASE("binary_boost_variant") { test_boost_variant(); } -BOOST_AUTO_TEST_CASE( portable_binary_boost_variant ) +TEST_CASE("portable_binary_boost_variant") { test_boost_variant(); } -BOOST_AUTO_TEST_CASE( xml_boost_variant ) +TEST_CASE("xml_boost_variant") { test_boost_variant(); } -BOOST_AUTO_TEST_CASE( json_boost_variant ) +TEST_CASE("json_boost_variant") { test_boost_variant(); } - +TEST_SUITE_END(); diff --git a/unittests/boost_variant.hpp b/unittests/boost_variant.hpp new file mode 100644 index 000000000..bedb6a89a --- /dev/null +++ b/unittests/boost_variant.hpp @@ -0,0 +1,70 @@ +/* + Copyright (c) 2015, Kyle Fleming + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_BOOST_VARIANT_H_ +#define CEREAL_TEST_BOOST_VARIANT_H_ + +#include "common.hpp" +#include + +template inline +void test_boost_variant() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + boost::variant o_bv1 = random_value(gen); + boost::variant o_bv2 = random_value(gen); + boost::variant o_bv3 = random_basic_string(gen); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_bv1); + oar(o_bv2); + oar(o_bv3); + } + + decltype(o_bv1) i_bv1; + decltype(o_bv2) i_bv2; + decltype(o_bv3) i_bv3; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_bv1); + iar(i_bv2); + iar(i_bv3); + } + + CHECK_EQ( boost::get(i_bv1), boost::get(o_bv1) ); + CHECK_EQ( boost::get(i_bv2), doctest::Approx(boost::get(o_bv2)).epsilon(1e-5) ); + CHECK_EQ( boost::get(i_bv3), boost::get(o_bv3) ); +} + +#endif // CEREAL_TEST_BOOST_VARIANT_H_ diff --git a/unittests/chrono.cpp b/unittests/chrono.cpp index c71238a6c..b175decdd 100644 --- a/unittests/chrono.cpp +++ b/unittests/chrono.cpp @@ -24,100 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "chrono.hpp" -template -void test_chrono() -{ - for(int ii=0; ii<100; ++ii) - { - auto o_timePoint1 = std::chrono::system_clock::now(); - #ifndef CEREAL_OLDER_GCC - auto o_timePoint2 = std::chrono::steady_clock::now(); - #endif // CEREAL_OLDER_GCC - auto o_timePoint3 = std::chrono::high_resolution_clock::now(); - - auto o_duration1 = std::chrono::system_clock::now() - o_timePoint1; - #ifndef CEREAL_OLDER_GCC - auto o_duration2 = std::chrono::steady_clock::now() - o_timePoint2; - #endif // CEREAL_OLDER_GCC - auto o_duration3 = std::chrono::high_resolution_clock::now() - o_timePoint3; - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_timePoint1); - #ifndef CEREAL_OLDER_GCC - oar(o_timePoint2); - #endif // CEREAL_OLDER_GCC - oar(o_timePoint3); - oar(o_duration1); - #ifndef CEREAL_OLDER_GCC - oar(o_duration2); - #endif // CEREAL_OLDER_GCC - oar(o_duration3); - } - - decltype(o_timePoint1) i_timePoint1; - #ifndef CEREAL_OLDER_GCC - decltype(o_timePoint2) i_timePoint2; - #endif // CEREAL_OLDER_GCC - decltype(o_timePoint3) i_timePoint3; - decltype(o_duration1) i_duration1; - #ifndef CEREAL_OLDER_GCC - decltype(o_duration2) i_duration2; - #endif // CEREAL_OLDER_GCC - decltype(o_duration3) i_duration3; +TEST_SUITE("chrono"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_timePoint1); - #ifndef CEREAL_OLDER_GCC - iar(i_timePoint2); - #endif // CEREAL_OLDER_GCC - iar(i_timePoint3); - iar(i_duration1); - #ifndef CEREAL_OLDER_GCC - iar(i_duration2); - #endif // CEREAL_OLDER_GCC - iar(i_duration3); - } - - BOOST_CHECK( o_timePoint1 == i_timePoint1 ); - #ifndef CEREAL_OLDER_GCC - BOOST_CHECK( o_timePoint2 == i_timePoint2 ); - #endif // CEREAL_OLDER_GCC - BOOST_CHECK( o_timePoint3 == i_timePoint3 ); - BOOST_CHECK( o_duration1 == i_duration1 ); - #ifndef CEREAL_OLDER_GCC - BOOST_CHECK( o_duration2 == i_duration2 ); - #endif // CEREAL_OLDER_GCC - BOOST_CHECK( o_duration3 == i_duration3 ); - } -} - -BOOST_AUTO_TEST_CASE( binary_chrono ) +TEST_CASE("binary_chrono") { test_chrono(); } -BOOST_AUTO_TEST_CASE( portable_binary_chrono ) +TEST_CASE("portable_binary_chrono") { test_chrono(); } -BOOST_AUTO_TEST_CASE( xml_chrono ) +TEST_CASE("xml_chrono") { test_chrono(); } -BOOST_AUTO_TEST_CASE( json_chrono ) +TEST_CASE("json_chrono") { test_chrono(); } - +TEST_SUITE_END(); diff --git a/unittests/chrono.hpp b/unittests/chrono.hpp new file mode 100644 index 000000000..3e66623a5 --- /dev/null +++ b/unittests/chrono.hpp @@ -0,0 +1,105 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_CHRONO_H_ +#define CEREAL_TEST_CHRONO_H_ + +#include "common.hpp" + +template inline +void test_chrono() +{ + for(int ii=0; ii<100; ++ii) + { + auto o_timePoint1 = std::chrono::system_clock::now(); + #ifndef CEREAL_OLDER_GCC + auto o_timePoint2 = std::chrono::steady_clock::now(); + #endif // CEREAL_OLDER_GCC + auto o_timePoint3 = std::chrono::high_resolution_clock::now(); + + auto o_duration1 = std::chrono::system_clock::now() - o_timePoint1; + #ifndef CEREAL_OLDER_GCC + auto o_duration2 = std::chrono::steady_clock::now() - o_timePoint2; + #endif // CEREAL_OLDER_GCC + auto o_duration3 = std::chrono::high_resolution_clock::now() - o_timePoint3; + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_timePoint1); + #ifndef CEREAL_OLDER_GCC + oar(o_timePoint2); + #endif // CEREAL_OLDER_GCC + oar(o_timePoint3); + oar(o_duration1); + #ifndef CEREAL_OLDER_GCC + oar(o_duration2); + #endif // CEREAL_OLDER_GCC + oar(o_duration3); + } + + decltype(o_timePoint1) i_timePoint1; + #ifndef CEREAL_OLDER_GCC + decltype(o_timePoint2) i_timePoint2; + #endif // CEREAL_OLDER_GCC + decltype(o_timePoint3) i_timePoint3; + decltype(o_duration1) i_duration1; + #ifndef CEREAL_OLDER_GCC + decltype(o_duration2) i_duration2; + #endif // CEREAL_OLDER_GCC + decltype(o_duration3) i_duration3; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_timePoint1); + #ifndef CEREAL_OLDER_GCC + iar(i_timePoint2); + #endif // CEREAL_OLDER_GCC + iar(i_timePoint3); + iar(i_duration1); + #ifndef CEREAL_OLDER_GCC + iar(i_duration2); + #endif // CEREAL_OLDER_GCC + iar(i_duration3); + } + + CHECK_EQ( o_timePoint1, i_timePoint1 ); + #ifndef CEREAL_OLDER_GCC + CHECK_EQ( o_timePoint2, i_timePoint2 ); + #endif // CEREAL_OLDER_GCC + CHECK_EQ( o_timePoint3, i_timePoint3 ); + CHECK_EQ( o_duration1, i_duration1 ); + #ifndef CEREAL_OLDER_GCC + CHECK_EQ( o_duration2, i_duration2 ); + #endif // CEREAL_OLDER_GCC + CHECK_EQ( o_duration3, i_duration3 ); + } +} + +#endif // CEREAL_TEST_CHRONO_H_ diff --git a/unittests/common.hpp b/unittests/common.hpp index c126e3f06..5376d0a43 100644 --- a/unittests/common.hpp +++ b/unittests/common.hpp @@ -47,7 +47,6 @@ #include #include #include -#include #include #include @@ -56,32 +55,11 @@ #include #include -#include -#if BOOST_VERSION >= 105900 -#include +#include "doctest.h" -namespace boost -{ - namespace test_tools - { - namespace tt_detail - { - template - struct print_log_value< ::std::pair > - { - void operator()(::std::ostream & os, ::std::pair const & p ) - { - os << "([" << p.first << "], [" << p.second << "])"; - } - }; - } - } -} - -#endif // appropriate boost version - -namespace boost +namespace std { + // Ostream overload for std::pair template inline ::std::ostream & operator<<(::std::ostream & os, ::std::pair const & p) { @@ -90,6 +68,22 @@ namespace boost } } +// Checks that collections have equal size and all elements are the same +template inline +void check_collection( T const & a, T const & b ) +{ + auto aIter = std::begin(a); + auto aEnd = std::end(a); + auto bIter = std::begin(b); + auto bEnd = std::end(b); + + CHECK_EQ( std::distance(aIter, aEnd), std::distance(bIter, bEnd) ); + + for( ; aIter != aEnd; ++aIter, ++bIter ) + CHECK_EQ( *aIter, *bIter ); +} + +// Random Number Generation =============================================== template inline typename std::enable_if::value, T>::type random_value(std::mt19937 & gen) @@ -133,6 +127,7 @@ std::string random_binary_string(std::mt19937 & gen) return s; } +// Generic struct useful for testing many serialization functions struct StructBase { StructBase() {} @@ -190,7 +185,7 @@ struct StructExternalSerialize : StructBase StructExternalSerialize(int x_, int y_) : StructBase{x_,y_} {} }; - template +template void serialize(Archive & ar, StructExternalSerialize & s) { ar(s.x, s.y); @@ -202,19 +197,18 @@ struct StructExternalSplit : StructBase StructExternalSplit(int x_, int y_) : StructBase{x_,y_} {} }; - template inline +template inline void save(Archive & ar, StructExternalSplit const & s) { ar(s.x, s.y); } - template inline +template inline void load(Archive & ar, StructExternalSplit & s) { ar(s.x, s.y); } - template struct StructHash { public: @@ -225,5 +219,5 @@ struct StructHash { return h1 ^ ( h2 << 1 ); } }; - + #endif // CEREAL_TEST_COMMON_H_ diff --git a/unittests/complex.cpp b/unittests/complex.cpp index 786e0da10..168d1038c 100644 --- a/unittests/complex.cpp +++ b/unittests/complex.cpp @@ -24,73 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "complex.hpp" -template -void test_complex() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rngF = [&](){ return random_value(gen); }; - auto rngD = [&](){ return random_value(gen); }; - auto rngLD = [&](){ return random_value(gen); }; - - for(int ii=0; ii<100; ++ii) - { - std::complex o_float( rngF(), rngF() ); - std::complex o_double( rngD(), rngD() ); - std::complex o_ldouble( rngLD(), rngLD() ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_float); - oar(o_double); - oar(o_ldouble); - } - - std::complex i_float; - std::complex i_double; - std::complex i_ldouble; +TEST_SUITE("complex"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_float); - iar(i_double); - iar(i_ldouble); - } - - BOOST_CHECK_EQUAL( o_float, i_float ); - BOOST_CHECK_CLOSE( o_double.real(), i_double.real(), 1e-5); - BOOST_CHECK_CLOSE( o_double.imag(), i_double.imag(), 1e-5); - BOOST_CHECK_CLOSE( o_ldouble.real(), i_ldouble.real(), 1e-5); - BOOST_CHECK_CLOSE( o_ldouble.imag(), i_ldouble.imag(), 1e-5); - } -} - -BOOST_AUTO_TEST_CASE( binary_complex ) +TEST_CASE("binary_complex") { test_complex(); } -BOOST_AUTO_TEST_CASE( portable_binary_complex ) +TEST_CASE("portable_binary_complex") { test_complex(); } -BOOST_AUTO_TEST_CASE( xml_complex ) +TEST_CASE("xml_complex") { test_complex(); } -BOOST_AUTO_TEST_CASE( json_complex ) +TEST_CASE("json_complex") { test_complex(); } - +TEST_SUITE_END(); diff --git a/unittests/complex.hpp b/unittests/complex.hpp new file mode 100644 index 000000000..ebd7e357a --- /dev/null +++ b/unittests/complex.hpp @@ -0,0 +1,77 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_COMPLEX_H_ +#define CEREAL_TEST_COMPLEX_H_ +#include "common.hpp" + +template inline +void test_complex() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rngF = [&](){ return random_value(gen); }; + auto rngD = [&](){ return random_value(gen); }; + auto rngLD = [&](){ return random_value(gen); }; + + for(int ii=0; ii<100; ++ii) + { + std::complex o_float( rngF(), rngF() ); + std::complex o_double( rngD(), rngD() ); + std::complex o_ldouble( rngLD(), rngLD() ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_float); + oar(o_double); + oar(o_ldouble); + } + + std::complex i_float; + std::complex i_double; + std::complex i_ldouble; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_float); + iar(i_double); + iar(i_ldouble); + } + + CHECK_EQ( o_float, i_float ); + CHECK_EQ( o_double.real(), doctest::Approx(i_double.real()).epsilon(1e-5) ); + CHECK_EQ( o_double.imag(), doctest::Approx(i_double.imag()).epsilon(1e-5) ); + CHECK_EQ( o_ldouble.real(), doctest::Approx(i_ldouble.real()).epsilon(1e-5L) ); + CHECK_EQ( o_ldouble.imag(), doctest::Approx(i_ldouble.imag()).epsilon(1e-5L) ); + } +} + +#endif // CEREAL_TEST_COMPLEX_H_ diff --git a/unittests/deque.cpp b/unittests/deque.cpp index 9bf694d9d..cbfaea1b4 100644 --- a/unittests/deque.cpp +++ b/unittests/deque.cpp @@ -24,95 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "deque.hpp" -template -void test_deque() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::deque o_poddeque(100); - for(auto & elem : o_poddeque) - elem = random_value(gen); - - std::deque o_iserdeque(100); - for(auto & elem : o_iserdeque) - elem = StructInternalSerialize( random_value(gen), random_value(gen) ); - - std::deque o_ispldeque(100); - for(auto & elem : o_ispldeque) - elem = StructInternalSplit( random_value(gen), random_value(gen) ); - - std::deque o_eserdeque(100); - for(auto & elem : o_eserdeque) - elem = StructExternalSerialize( random_value(gen), random_value(gen) ); - - std::deque o_espldeque(100); - for(auto & elem : o_espldeque) - elem = StructExternalSplit( random_value(gen), random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_poddeque); - oar(o_iserdeque); - oar(o_ispldeque); - oar(o_eserdeque); - oar(o_espldeque); - } +TEST_SUITE("deque"); - std::deque i_poddeque; - std::deque i_iserdeque; - std::deque i_ispldeque; - std::deque i_eserdeque; - std::deque i_espldeque; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_poddeque); - iar(i_iserdeque); - iar(i_ispldeque); - iar(i_eserdeque); - iar(i_espldeque); - } - - BOOST_CHECK_EQUAL(i_poddeque.size(), o_poddeque.size()); - BOOST_CHECK_EQUAL(i_iserdeque.size(), o_iserdeque.size()); - BOOST_CHECK_EQUAL(i_ispldeque.size(), o_ispldeque.size()); - BOOST_CHECK_EQUAL(i_eserdeque.size(), o_eserdeque.size()); - BOOST_CHECK_EQUAL(i_espldeque.size(), o_espldeque.size()); - - BOOST_CHECK_EQUAL_COLLECTIONS(i_poddeque.begin(), i_poddeque.end(), o_poddeque.begin(), o_poddeque.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserdeque.begin(), i_iserdeque.end(), o_iserdeque.begin(), o_iserdeque.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_ispldeque.begin(), i_ispldeque.end(), o_ispldeque.begin(), o_ispldeque.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserdeque.begin(), i_eserdeque.end(), o_eserdeque.begin(), o_eserdeque.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_espldeque.begin(), i_espldeque.end(), o_espldeque.begin(), o_espldeque.end()); - } -} - -BOOST_AUTO_TEST_CASE( binary_dequeue ) +TEST_CASE("binary_dequeue") { test_deque(); } -BOOST_AUTO_TEST_CASE( portable_binary_dequeue ) +TEST_CASE("portable_binary_dequeue") { test_deque(); } -BOOST_AUTO_TEST_CASE( xml_dequeue ) +TEST_CASE("xml_dequeue") { test_deque(); } -BOOST_AUTO_TEST_CASE( json_dequeue ) +TEST_CASE("json_dequeue") { test_deque(); } + +TEST_SUITE_END(); diff --git a/unittests/deque.hpp b/unittests/deque.hpp new file mode 100644 index 000000000..b129a1e53 --- /dev/null +++ b/unittests/deque.hpp @@ -0,0 +1,101 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_DEQUE_H_ +#define CEREAL_TEST_DEQUE_H_ +#include "common.hpp" + +template +void test_deque() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::deque o_poddeque(100); + for(auto & elem : o_poddeque) + elem = random_value(gen); + + std::deque o_iserdeque(100); + for(auto & elem : o_iserdeque) + elem = StructInternalSerialize( random_value(gen), random_value(gen) ); + + std::deque o_ispldeque(100); + for(auto & elem : o_ispldeque) + elem = StructInternalSplit( random_value(gen), random_value(gen) ); + + std::deque o_eserdeque(100); + for(auto & elem : o_eserdeque) + elem = StructExternalSerialize( random_value(gen), random_value(gen) ); + + std::deque o_espldeque(100); + for(auto & elem : o_espldeque) + elem = StructExternalSplit( random_value(gen), random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_poddeque); + oar(o_iserdeque); + oar(o_ispldeque); + oar(o_eserdeque); + oar(o_espldeque); + } + + std::deque i_poddeque; + std::deque i_iserdeque; + std::deque i_ispldeque; + std::deque i_eserdeque; + std::deque i_espldeque; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_poddeque); + iar(i_iserdeque); + iar(i_ispldeque); + iar(i_eserdeque); + iar(i_espldeque); + } + + CHECK_EQ(i_poddeque.size(), o_poddeque.size()); + CHECK_EQ(i_iserdeque.size(), o_iserdeque.size()); + CHECK_EQ(i_ispldeque.size(), o_ispldeque.size()); + CHECK_EQ(i_eserdeque.size(), o_eserdeque.size()); + CHECK_EQ(i_espldeque.size(), o_espldeque.size()); + + check_collection(i_poddeque, o_poddeque ); + check_collection(i_iserdeque, o_iserdeque); + check_collection(i_ispldeque, o_ispldeque); + check_collection(i_eserdeque, o_eserdeque); + check_collection(i_espldeque, o_espldeque); + } +} + +#endif // CEREAL_TEST_DEQUE_H_ diff --git a/unittests/doctest.h b/unittests/doctest.h new file mode 100644 index 000000000..2edf60469 --- /dev/null +++ b/unittests/doctest.h @@ -0,0 +1,3374 @@ +// ====================================================================== +// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == +// ====================================================================== +// +// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD +// +// Copyright (c) 2016 Viktor Kirilov +// +// Distributed under the MIT Software License +// See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/MIT +// +// The documentation can be found at the library's page: +// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= +// +// The library is heavily influenced by Catch - https://github.com/philsquared/Catch +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/philsquared/Catch/blob/master/LICENSE_1_0.txt +// +// The concept of subcases (sections in Catch) and expression decomposition are from there. +// Some parts of the code are taken directly: +// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> +// - the Approx() helper class for floating point comparison +// - colors in the console +// - breaking into a debugger +// +// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/martinmoene/lest/blob/master/LICENSE_1_0.txt +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= + +// Suppress this globally (without push/pop) - there is no way to silence it in the +// expression decomposition macros _Pragma() in macros doesn't work for the c++ front-end of g++ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543 +// Also the warning is completely worthless nowadays - http://stackoverflow.com/questions/14016993 +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic ignored "-Waggregate-return" +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic push +#endif // > gcc 4.6 +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Weffc++" +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#pragma GCC diagnostic ignored "-Winline" +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif // > gcc 4.6 +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7) +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif // > gcc 4.7 +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3) +#pragma GCC diagnostic ignored "-Wuseless-cast" +#endif // > gcc 5.3 +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) // The compiler encountered a deprecated declaration +#pragma warning(disable : 4706) // assignment within conditional expression +#pragma warning(disable : 4512) // 'class' : assignment operator could not be generated +#pragma warning(disable : 4127) // conditional expression is constant +#endif // _MSC_VER + +#ifndef DOCTEST_LIBRARY_INCLUDED +#define DOCTEST_LIBRARY_INCLUDED + +#define DOCTEST_VERSION_MAJOR 1 +#define DOCTEST_VERSION_MINOR 1 +#define DOCTEST_VERSION_PATCH 2 +#define DOCTEST_VERSION_STR "1.1.2" + +#define DOCTEST_VERSION \ + (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +// ================================================================================================= +// == MODERN C++ FEATURE DETECTION ================================================================= +// ================================================================================================= + +#if __cplusplus >= 201103L +#ifndef DOCTEST_CONFIG_WITH_NULLPTR +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // DOCTEST_CONFIG_WITH_NULLPTR +#ifndef DOCTEST_CONFIG_WITH_LONG_LONG +#define DOCTEST_CONFIG_WITH_LONG_LONG +#endif // DOCTEST_CONFIG_WITH_LONG_LONG +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // __cplusplus >= 201103L + +// nullptr + +#ifndef DOCTEST_CONFIG_WITH_NULLPTR +#ifdef __clang__ +#if __has_feature(cxx_nullptr) +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // __has_feature(cxx_nullptr) +#endif // __clang__ + +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // __GNUC__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) // MSVC 2010 +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // _MSC_VER +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +#if defined(DOCTEST_CONFIG_NO_NULLPTR) && defined(DOCTEST_CONFIG_WITH_NULLPTR) +#undef DOCTEST_CONFIG_WITH_NULLPTR +#endif // DOCTEST_CONFIG_NO_NULLPTR + +// long long + +#ifndef DOCTEST_CONFIG_WITH_LONG_LONG +#if !defined(DOCTEST_CONFIG_WITH_LONG_LONG) && defined(_MSC_VER) && (_MSC_VER >= 1400) +#define DOCTEST_CONFIG_WITH_LONG_LONG +#endif // _MSC_VER +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#if defined(DOCTEST_CONFIG_NO_LONG_LONG) && defined(DOCTEST_CONFIG_WITH_LONG_LONG) +#undef DOCTEST_CONFIG_WITH_LONG_LONG +#endif // DOCTEST_CONFIG_NO_LONG_LONG + +// static_assert + +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#ifdef __clang__ +#if __has_feature(cxx_static_assert) +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // __has_feature(cxx_static_assert) +#endif // __clang__ + +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // __GNUC__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) // MSVC 2010 +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // _MSC_VER +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + +#if defined(DOCTEST_CONFIG_NO_STATIC_ASSERT) && defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) +#undef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // DOCTEST_CONFIG_NO_STATIC_ASSERT + +#if defined(DOCTEST_CONFIG_WITH_NULLPTR) || defined(DOCTEST_CONFIG_WITH_LONG_LONG) || \ + defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) +#define DOCTEST_NO_CPP11_COMPAT +#endif // c++11 stuff + +#if defined(__clang__) && defined(DOCTEST_NO_CPP11_COMPAT) +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif // __clang__ && DOCTEST_NO_CPP11_COMPAT + +// ================================================================================================= +// == MODERN C++ FEATURE DETECTION END ============================================================= +// ================================================================================================= + +// internal macros for string concatenation and anonymous variable name generation +#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 +#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) +#ifdef __COUNTER__ // not standard and may be missing for some compilers +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) +#else // __COUNTER__ +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) +#endif // __COUNTER__ + +// macro for making a string out of an identifier +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) + +// for concatenating literals and making the result a string +#define DOCTEST_STR_CONCAT_TOSTR(s1, s2) DOCTEST_TOSTR(s1) DOCTEST_TOSTR(s2) + +// counts the number of elements in a C string +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x& +#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x +#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE + +// not using __APPLE__ because... this is how Catch does it +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_IPHONE +#elif defined(_WIN32) || defined(_MSC_VER) +#define DOCTEST_PLATFORM_WINDOWS +#else +#define DOCTEST_PLATFORM_LINUX +#endif + +#define DOCTEST_GCS() (*doctest::detail::getTestsContextState()) + +// should probably take a look at https://github.com/scottt/debugbreak +#ifdef DOCTEST_PLATFORM_MAC +// The following code snippet based on: +// http://cocoawithlove.com/2008/03/break-into-debugger.html +#if defined(__ppc64__) || defined(__ppc__) +#define DOCTEST_BREAK_INTO_DEBUGGER() \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" : : : "memory", "r0", "r3", "r4") +#else // __ppc64__ || __ppc__ +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) +#endif // __ppc64__ || __ppc__ +#elif defined(_MSC_VER) +#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() +#elif defined(__MINGW32__) +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() +#else // linux +#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) +#endif // linux + +#define DOCTEST_BREAK_INTO_DEBUGGER_CHECKED() \ + if(doctest::detail::isDebuggerActive() && !DOCTEST_GCS().no_breaks) \ + DOCTEST_BREAK_INTO_DEBUGGER(); + +#ifdef __clang__ +// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) +#include +#endif // __clang__ + +#ifdef _LIBCPP_VERSION +// not forward declaring ostream for libc++ because I had some problems (inline namespaces vs c++98) +// so the header is used - also it is very light and doesn't drag a ton of stuff +#include +#else // _LIBCPP_VERSION +#ifndef DOCTEST_CONFIG_USE_IOSFWD +namespace std +{ +template +struct char_traits; +template <> +struct char_traits; +template +class basic_ostream; +typedef basic_ostream > ostream; +} +#else // DOCTEST_CONFIG_USE_IOSFWD +#include +#endif // DOCTEST_CONFIG_USE_IOSFWD +#endif // _LIBCPP_VERSION + +// static assert macro - because of the c++98 support requires that the message is an +// identifier (no spaces and not a C string) - example without quotes: I_am_a_message +// taken from here: http://stackoverflow.com/a/1980156/3162383 +#ifdef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_STATIC_ASSERT(expression, message) static_assert(expression, #message) +#else // DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_STATIC_ASSERT(expression, message) \ + struct DOCTEST_CAT(__static_assertion_at_line_, __LINE__) \ + { \ + doctest::detail::static_assert_impl::StaticAssertion((expression))> \ + DOCTEST_CAT(DOCTEST_CAT(DOCTEST_CAT(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), \ + _), \ + message); \ + }; \ + typedef doctest::detail::static_assert_impl::StaticAssertionTest \ + DOCTEST_CAT(__static_assertion_test_at_line_, __LINE__) +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +#ifdef _LIBCPP_VERSION +#include +#else // _LIBCPP_VERSION +namespace std +{ typedef decltype(nullptr) nullptr_t; } +#endif // _LIBCPP_VERSION +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +namespace doctest +{ +class String +{ + char* m_str; + + void copy(const String& other); + +public: + String(const char* in = ""); + String(const String& other); + ~String(); + + String& operator=(const String& other); + + String operator+(const String& other) const; + String& operator+=(const String& other); + + char& operator[](unsigned pos) { return m_str[pos]; } + const char& operator[](unsigned pos) const { return m_str[pos]; } + + char* c_str() { return m_str; } + const char* c_str() const { return m_str; } + + unsigned size() const; + unsigned length() const; + + int compare(const char* other, bool no_case = false) const; + int compare(const String& other, bool no_case = false) const; +}; + +// clang-format off +inline bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } +inline bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } +inline bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } +inline bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } +inline bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } +inline bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } +// clang-format on + +std::ostream& operator<<(std::ostream& stream, const String& in); + +namespace detail +{ +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT + namespace static_assert_impl + { + template + struct StaticAssertion; + + template <> + struct StaticAssertion + {}; + + template + struct StaticAssertionTest + {}; + } // namespace static_assert_impl +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + + template + struct deferred_false + { static const bool value = false; }; + + namespace has_insertion_operator_impl + { + typedef char no; + typedef char yes[2]; + + struct any_t + { + template + any_t(const DOCTEST_REF_WRAP(T)); + }; + + yes& testStreamable(std::ostream&); + no testStreamable(no); + + no operator<<(const std::ostream&, const any_t&); + + template + struct has_insertion_operator + { + static std::ostream& s; + static const DOCTEST_REF_WRAP(T) t; + static const bool value = sizeof(testStreamable(s << t)) == sizeof(yes); + }; + } // namespace has_insertion_operator_impl + + template + struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator + {}; + + std::ostream* createStream(); + String getStreamResult(std::ostream*); + void freeStream(std::ostream*); + + template + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T)) { + return "{?}"; + } + }; + + template <> + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + std::ostream* stream = createStream(); + *stream << in; + String result = getStreamResult(stream); + freeStream(stream); + return result; + } + }; + + String rawMemoryToString(const void* object, unsigned size); + + template + String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { + return rawMemoryToString(&object, sizeof(object)); + } +} // namespace detail + +template +struct StringMaker : detail::StringMakerBase::value> +{}; + +template +struct StringMaker +{ + template + static String convert(U* p) { + if(!p) + return "NULL"; + else + return detail::rawMemoryToString(p); + } +}; + +template +struct StringMaker +{ + static String convert(R C::*p) { + if(!p) + return "NULL"; + else + return detail::rawMemoryToString(p); + } +}; + +template +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(char* in); +String toString(const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(bool in); +String toString(float in); +String toString(double in); +String toString(double long in); + +String toString(char in); +String toString(char unsigned in); +String toString(int short in); +String toString(int short unsigned in); +String toString(int in); +String toString(int unsigned in); +String toString(int long in); +String toString(int long unsigned in); + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG +String toString(int long long in); +String toString(int long long unsigned in); +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +String toString(std::nullptr_t in); +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +class Approx +{ +public: + explicit Approx(double value); + + Approx(Approx const& other) + : m_epsilon(other.m_epsilon) + , m_scale(other.m_scale) + , m_value(other.m_value) {} + + Approx operator()(double value) { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; + } + + friend bool operator==(double lhs, Approx const& rhs); + friend bool operator==(Approx const& lhs, double rhs) { return operator==(rhs, lhs); } + friend bool operator!=(double lhs, Approx const& rhs) { return !operator==(lhs, rhs); } + friend bool operator!=(Approx const& lhs, double rhs) { return !operator==(rhs, lhs); } + + Approx& epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale(double newScale) { + m_scale = newScale; + return *this; + } + + String toString() const; + +private: + double m_epsilon; + double m_scale; + double m_value; +}; + +template <> +inline String toString(const DOCTEST_REF_WRAP(Approx) value) { + return value.toString(); +} + +#if !defined(DOCTEST_CONFIG_DISABLE) + +namespace detail +{ + // the function type this library works with + typedef void (*funcType)(void); + + namespace assertType + { + enum Enum + { + // macro traits + + is_warn = 1, + is_check = 2, + is_require = 4, + + is_throws = 8, + is_throws_as = 16, + is_nothrow = 32, + + is_fast = 64, // not checked anywhere - used just to distinguish the types + is_false = 128, + is_unary = 256, + + is_eq = 512, + is_ne = 1024, + + is_lt = 2048, + is_gt = 4096, + + is_ge = 8192, + is_le = 16384, + + // macro types + + DT_WARN = is_warn, + DT_CHECK = is_check, + DT_REQUIRE = is_require, + + DT_WARN_FALSE = is_false | is_warn, + DT_CHECK_FALSE = is_false | is_check, + DT_REQUIRE_FALSE = is_false | is_require, + + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, + + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, + + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, + + DT_WARN_EQ = is_eq | is_warn, + DT_CHECK_EQ = is_eq | is_check, + DT_REQUIRE_EQ = is_eq | is_require, + + DT_WARN_NE = is_ne | is_warn, + DT_CHECK_NE = is_ne | is_check, + DT_REQUIRE_NE = is_ne | is_require, + + DT_WARN_GT = is_gt | is_warn, + DT_CHECK_GT = is_gt | is_check, + DT_REQUIRE_GT = is_gt | is_require, + + DT_WARN_LT = is_lt | is_warn, + DT_CHECK_LT = is_lt | is_check, + DT_REQUIRE_LT = is_lt | is_require, + + DT_WARN_GE = is_ge | is_warn, + DT_CHECK_GE = is_ge | is_check, + DT_REQUIRE_GE = is_ge | is_require, + + DT_WARN_LE = is_le | is_warn, + DT_CHECK_LE = is_le | is_check, + DT_REQUIRE_LE = is_le | is_require, + + DT_WARN_UNARY = is_unary | is_warn, + DT_CHECK_UNARY = is_unary | is_check, + DT_REQUIRE_UNARY = is_unary | is_require, + + DT_WARN_UNARY_FALSE = is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_false | is_unary | is_require, + + DT_FAST_WARN_EQ = is_fast | is_eq | is_warn, + DT_FAST_CHECK_EQ = is_fast | is_eq | is_check, + DT_FAST_REQUIRE_EQ = is_fast | is_eq | is_require, + + DT_FAST_WARN_NE = is_fast | is_ne | is_warn, + DT_FAST_CHECK_NE = is_fast | is_ne | is_check, + DT_FAST_REQUIRE_NE = is_fast | is_ne | is_require, + + DT_FAST_WARN_GT = is_fast | is_gt | is_warn, + DT_FAST_CHECK_GT = is_fast | is_gt | is_check, + DT_FAST_REQUIRE_GT = is_fast | is_gt | is_require, + + DT_FAST_WARN_LT = is_fast | is_lt | is_warn, + DT_FAST_CHECK_LT = is_fast | is_lt | is_check, + DT_FAST_REQUIRE_LT = is_fast | is_lt | is_require, + + DT_FAST_WARN_GE = is_fast | is_ge | is_warn, + DT_FAST_CHECK_GE = is_fast | is_ge | is_check, + DT_FAST_REQUIRE_GE = is_fast | is_ge | is_require, + + DT_FAST_WARN_LE = is_fast | is_le | is_warn, + DT_FAST_CHECK_LE = is_fast | is_le | is_check, + DT_FAST_REQUIRE_LE = is_fast | is_le | is_require, + + DT_FAST_WARN_UNARY = is_fast | is_unary | is_warn, + DT_FAST_CHECK_UNARY = is_fast | is_unary | is_check, + DT_FAST_REQUIRE_UNARY = is_fast | is_unary | is_require, + + DT_FAST_WARN_UNARY_FALSE = is_fast | is_false | is_unary | is_warn, + DT_FAST_CHECK_UNARY_FALSE = is_fast | is_false | is_unary | is_check, + DT_FAST_REQUIRE_UNARY_FALSE = is_fast | is_false | is_unary | is_require + }; + } // namespace assertType + + const char* getAssertString(assertType::Enum val); + + // clang-format off + template struct decay_array { typedef T type; }; + template struct decay_array { typedef T* type; }; + template struct decay_array { typedef T* type; }; + + template struct not_char_pointer { enum { value = true }; }; + template<> struct not_char_pointer { enum { value = false }; }; + template<> struct not_char_pointer { enum { value = false }; }; + + template struct can_use_op : not_char_pointer::type> {}; + + template struct enable_if {}; + template struct enable_if { typedef T type; }; + // clang-format on + + struct TestFailureException + {}; + + bool checkIfShouldThrow(assertType::Enum assert_type); + void fastAssertThrowIfFlagSet(int flags); + void throwException(); + bool always_false(); + + // a struct defining a registered test callback + struct TestData + { + // not used for determining uniqueness + const char* m_suite; // the test suite in which the test was added + const char* m_name; // name of the test function + funcType m_f; // a function pointer to the test function + + // fields by which uniqueness of test cases shall be determined + const char* m_file; // the file in which the test was registered + unsigned m_line; // the line where the test was registered + + TestData(const char* suite, const char* name, funcType f, const char* file, unsigned line) + : m_suite(suite) + , m_name(name) + , m_f(f) + , m_file(file) + , m_line(line) {} + + bool operator<(const TestData& other) const; + }; + + struct SubcaseSignature + { + const char* m_name; + const char* m_file; + int m_line; + + SubcaseSignature(const char* name, const char* file, int line) + : m_name(name) + , m_file(file) + , m_line(line) {} + + bool operator<(const SubcaseSignature& other) const; + }; + + struct Subcase + { + SubcaseSignature m_signature; + bool m_entered; + + Subcase(const char* name, const char* file, int line); + Subcase(const Subcase& other); + ~Subcase(); + + operator bool() const { return m_entered; } + }; + + template + String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, + const DOCTEST_REF_WRAP(R) rhs) { + return toString(lhs) + op + toString(rhs); + } + + struct Result + { + bool m_passed; + String m_decomposition; + +// to fix gcc 4.7 "-Winline" warnings +#if defined(__GNUC__) && !defined(__clang__) + __attribute__((noinline)) +#endif + ~Result() { + } + + Result(bool passed = false, const String& decomposition = String()) + : m_passed(passed) + , m_decomposition(decomposition) {} + + Result(const Result& other) + : m_passed(other.m_passed) + , m_decomposition(other.m_decomposition) {} + +// to fix gcc 4.7 "-Winline" warnings +#if defined(__GNUC__) && !defined(__clang__) + __attribute__((noinline)) +#endif + Result& + operator=(const Result& other) { + m_passed = other.m_passed; + m_decomposition = other.m_decomposition; + + return *this; + } + + operator bool() { return !m_passed; } + + void invert() { m_passed = !m_passed; } + + // clang-format off + // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence + template Result operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator== (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator!= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator<= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator>= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + template Result operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } + // clang-format on + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wdouble-promotion" +//#pragma clang diagnostic ignored "-Wconversion" +//#pragma clang diagnostic ignored "-Wfloat-equal" +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic push +#endif // > gcc 4.6 +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wsign-compare" +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) +#pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif // > gcc 4.5 +//#pragma GCC diagnostic ignored "-Wconversion" +//#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(push) +// http://stackoverflow.com/questions/39479163 what's the difference between C4018 and C4389 +#pragma warning(disable : 4389) // 'operator' : signed/unsigned mismatch +#pragma warning(disable : 4018) // 'expression' : signed/unsigned mismatch +//#pragma warning(disable : 4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation +#endif // _MSC_VER + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +// clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type + inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } + inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } + inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } + inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } + inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } + inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + + template DOCTEST_COMPARISON_RETURN_TYPE eq(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs == rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE ne(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs != rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE lt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs < rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE gt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs > rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE le(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs <= rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE ge(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs >= rhs; } + // clang-format on + + template + struct Expression_lhs + { + L lhs; + + Expression_lhs(L in) + : lhs(in) {} + + Expression_lhs(const Expression_lhs& other) + : lhs(other.lhs) {} + + operator Result() { return Result(!!lhs, toString(lhs)); } + +// clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + template Result operator==(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs == rhs, stringifyBinaryExpr(lhs, " == ", rhs)); } + template Result operator!=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs != rhs, stringifyBinaryExpr(lhs, " != ", rhs)); } + template Result operator< (const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs < rhs, stringifyBinaryExpr(lhs, " < " , rhs)); } + template Result operator<=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs <= rhs, stringifyBinaryExpr(lhs, " <= ", rhs)); } + template Result operator> (const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs > rhs, stringifyBinaryExpr(lhs, " > " , rhs)); } + template Result operator>=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs >= rhs, stringifyBinaryExpr(lhs, " >= ", rhs)); } +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + template Result operator==(const DOCTEST_REF_WRAP(R) rhs) { return Result(eq(lhs, rhs), stringifyBinaryExpr(lhs, " == ", rhs)); } + template Result operator!=(const DOCTEST_REF_WRAP(R) rhs) { return Result(ne(lhs, rhs), stringifyBinaryExpr(lhs, " != ", rhs)); } + template Result operator< (const DOCTEST_REF_WRAP(R) rhs) { return Result(lt(lhs, rhs), stringifyBinaryExpr(lhs, " < " , rhs)); } + template Result operator<=(const DOCTEST_REF_WRAP(R) rhs) { return Result(le(lhs, rhs), stringifyBinaryExpr(lhs, " <= ", rhs)); } + template Result operator> (const DOCTEST_REF_WRAP(R) rhs) { return Result(gt(lhs, rhs), stringifyBinaryExpr(lhs, " > " , rhs)); } + template Result operator>=(const DOCTEST_REF_WRAP(R) rhs) { return Result(ge(lhs, rhs), stringifyBinaryExpr(lhs, " >= ", rhs)); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + + // clang-format off + // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence + template int operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + template int operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } + // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the + // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... + template int operator<< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Please_Surround_The_Left_Shift_Operation_With_Parenthesis); return int(); } + template int operator>> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Please_Surround_The_Right_Shift_Operation_With_Parenthesis); return int(); } + // clang-format on + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic pop +#endif // > gcc 4.6 +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + struct ExpressionDecomposer + { + template + Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { + return Expression_lhs(operand); + } + }; + + // forward declarations of functions used by the macros + int regTest(void (*f)(void), unsigned line, const char* file, const char* name); + int setTestSuiteName(const char* name); + + void addFailedAssert(assertType::Enum assert_type); + + void logTestStart(const char* name, const char* file, unsigned line); + void logTestEnd(); + + void logTestCrashed(); + + void logAssert(bool passed, const char* decomposition, bool threw, const char* expr, + assertType::Enum assert_type, const char* file, int line); + + void logAssertThrows(bool threw, const char* expr, assertType::Enum assert_type, + const char* file, int line); + + void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const char* expr, + assertType::Enum assert_type, const char* file, int line); + + void logAssertNothrow(bool threw, const char* expr, assertType::Enum assert_type, + const char* file, int line); + + bool isDebuggerActive(); + void writeToDebugConsole(const String&); + + struct TestAccessibleContextState + { + bool success; // include successful assertions in output + bool no_throw; // to skip exceptions-related assertion macros + bool no_breaks; // to not break into the debugger + const TestData* currentTest; + bool hasLoggedCurrentTestStart; + int numAssertionsForCurrentTestcase; + }; + + struct ContextState; + + TestAccessibleContextState* getTestsContextState(); + + namespace binaryAssertComparison + { + enum Enum + { + eq = 0, + ne, + gt, + lt, + ge, + le + }; + } // namespace binaryAssertComparison + + // clang-format off + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; + template struct RelationalComparator<0, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return eq(lhs, rhs); } }; + template struct RelationalComparator<1, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ne(lhs, rhs); } }; + template struct RelationalComparator<2, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return gt(lhs, rhs); } }; + template struct RelationalComparator<3, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return lt(lhs, rhs); } }; + template struct RelationalComparator<4, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ge(lhs, rhs); } }; + template struct RelationalComparator<5, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return le(lhs, rhs); } }; + // clang-format on + + struct ResultBuilder + { + assertType::Enum m_assert_type; + const char* m_file; + int m_line; + const char* m_expr; + const char* m_exception_type; + + Result m_result; + bool m_threw; + bool m_threw_as; + bool m_failed; + + ResultBuilder(assertType::Enum assert_type, const char* file, int line, const char* expr, + const char* exception_type = ""); + +// to fix gcc 4.7 "-Winline" warnings +#if defined(__GNUC__) && !defined(__clang__) + __attribute__((noinline)) +#endif + ~ResultBuilder() { + } + + void setResult(const Result& res) { m_result = res; } + + template + void binary_assert(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { + m_result.m_passed = RelationalComparator()(lhs, rhs); + m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); + } + + template + void unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_result.m_passed = !!val; + m_result.m_decomposition = toString(val); + } + + bool log(); + void react() const; + }; + + namespace assertAction + { + enum Enum + { + nothing = 0, + dbgbreak = 1, + shouldthrow = 2 + }; + } // namespace assertAction + + template + int fast_binary_assert(assertType::Enum assert_type, const char* file, int line, + const char* lhs_str, const char* rhs_str, const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + String expr = String(lhs_str) + ", " + rhs_str; + const char* expr_str = expr.c_str(); + ResultBuilder rb(assert_type, file, line, expr_str); + + rb.m_result.m_passed = RelationalComparator()(lhs, rhs); + rb.m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); + + int res = 0; + + if(rb.log()) + res |= assertAction::dbgbreak; + + if(rb.m_failed && checkIfShouldThrow(assert_type)) + res |= assertAction::shouldthrow; + +#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + // ######################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ######################################################################################### + if(res & assertAction::dbgbreak) + DOCTEST_BREAK_INTO_DEBUGGER(); + fastAssertThrowIfFlagSet(res); +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + + return res; + } + + template + int fast_unary_assert(assertType::Enum assert_type, const char* file, int line, + const char* val_str, const DOCTEST_REF_WRAP(L) val) { + ResultBuilder rb(assert_type, file, line, val_str); + + rb.m_result.m_passed = !!val; + rb.m_result.m_decomposition = toString(val); + + int res = 0; + + if(rb.log()) + res |= assertAction::dbgbreak; + + if(rb.m_failed && checkIfShouldThrow(assert_type)) + res |= assertAction::shouldthrow; + +#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + // ######################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ######################################################################################### + if(res & assertAction::dbgbreak) + DOCTEST_BREAK_INTO_DEBUGGER(); + fastAssertThrowIfFlagSet(res); +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + + return res; + } +} // namespace detail + +#endif // DOCTEST_CONFIG_DISABLE + +class Context +{ +#if !defined(DOCTEST_CONFIG_DISABLE) + detail::ContextState* p; + + void parseArgs(int argc, const char* const* argv, bool withDefaults = false); + +#endif // DOCTEST_CONFIG_DISABLE + +public: + Context(int argc = 0, const char* const* argv = 0); + +// to fix gcc 4.7 "-Winline" warnings +#if defined(__GNUC__) && !defined(__clang__) + __attribute__((noinline)) +#endif + ~Context(); + + void applyCommandLine(int argc, const char* const* argv); + + void addFilter(const char* filter, const char* value); + void clearFilters(); + void setOption(const char* option, int value); + void setOption(const char* option, const char* value); + + bool shouldExit(); + + int run(); +}; + +} // namespace doctest + +// if registering is not disabled +#if !defined(DOCTEST_CONFIG_DISABLE) + +// registers the test by initializing a dummy var with a function +#if defined(__GNUC__) && !defined(__clang__) +#define DOCTEST_REGISTER_FUNCTION(f, name) \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ + doctest::detail::regTest(f, __LINE__, __FILE__, name); +#elif defined(__clang__) +#define DOCTEST_REGISTER_FUNCTION(f, name) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ + doctest::detail::regTest(f, __LINE__, __FILE__, name); \ + _Pragma("clang diagnostic pop") +#else // MSVC +#define DOCTEST_REGISTER_FUNCTION(f, name) \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ + doctest::detail::regTest(f, __LINE__, __FILE__, name); +#endif // MSVC + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace \ + { \ + struct der : base \ + { void f(); }; \ + static void func() { \ + der v; \ + v.f(); \ + } \ + DOCTEST_REGISTER_FUNCTION(func, name) \ + } \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + static void f(); \ + DOCTEST_REGISTER_FUNCTION(f, name) \ + inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(c, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for subcases +#if defined(__GNUC__) +#define DOCTEST_SUBCASE(name) \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) \ + __attribute__((unused)) = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) +#else // __GNUC__ +#define DOCTEST_SUBCASE(name) \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) +#endif // __GNUC__ + +// for starting a testsuite block +#if defined(__GNUC__) && !defined(__clang__) +#define DOCTEST_TEST_SUITE(name) \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ + doctest::detail::setTestSuiteName(name); \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#elif defined(__clang__) +#define DOCTEST_TEST_SUITE(name) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ + doctest::detail::setTestSuiteName(name); \ + _Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#else // MSVC +#define DOCTEST_TEST_SUITE(name) \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(name); \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#endif // MSVC + +// for ending a testsuite block +#if defined(__GNUC__) && !defined(__clang__) +#define DOCTEST_TEST_SUITE_END \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ + doctest::detail::setTestSuiteName(""); \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#elif defined(__clang__) +#define DOCTEST_TEST_SUITE_END \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(""); \ + _Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#else // MSVC +#define DOCTEST_TEST_SUITE_END \ + static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(""); \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#endif // MSVC + +#define DOCTEST_ASSERT_LOG_AND_REACT(rb) \ + if(rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + rb.react() + +#define DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, __FILE__, \ + __LINE__, #expr); \ + try { \ + _DOCTEST_RB.setResult(doctest::detail::ExpressionDecomposer() << expr); \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); + +#if defined(__clang__) +#define DOCTEST_ASSERT_PROXY(expr, assert_type) \ + do { \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Woverloaded-shift-op-parentheses\"") \ + DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ + _Pragma("clang diagnostic pop") \ + } while(doctest::detail::always_false()) +#else // __clang__ +#define DOCTEST_ASSERT_PROXY(expr, assert_type) \ + do { \ + DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ + } while(doctest::detail::always_false()) +#endif // __clang__ + +#define DOCTEST_WARN(expr) DOCTEST_ASSERT_PROXY(expr, DT_WARN) +#define DOCTEST_CHECK(expr) DOCTEST_ASSERT_PROXY(expr, DT_CHECK) +#define DOCTEST_REQUIRE(expr) DOCTEST_ASSERT_PROXY(expr, DT_REQUIRE) + +#define DOCTEST_WARN_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_WARN_FALSE) +#define DOCTEST_CHECK_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_CHECK_FALSE) +#define DOCTEST_REQUIRE_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_REQUIRE_FALSE) + +#define DOCTEST_ASSERT_THROWS(expr, assert_type) \ + do { \ + if(!DOCTEST_GCS().no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #expr); \ + try { \ + expr; \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while(doctest::detail::always_false()) + +#define DOCTEST_ASSERT_THROWS_AS(expr, as, assert_type) \ + do { \ + if(!DOCTEST_GCS().no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #expr, #as); \ + try { \ + expr; \ + } catch(as) { \ + _DOCTEST_RB.m_threw = true; \ + _DOCTEST_RB.m_threw_as = true; \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while(doctest::detail::always_false()) + +#define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \ + do { \ + if(!DOCTEST_GCS().no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #expr); \ + try { \ + expr; \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while(doctest::detail::always_false()) + +#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_WARN_THROWS) +#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_CHECK_THROWS) +#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_REQUIRE_THROWS) + +#define DOCTEST_WARN_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_WARN_THROWS_AS) +#define DOCTEST_CHECK_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_CHECK_THROWS_AS) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_REQUIRE_THROWS_AS) + +#define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW) +#define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW) +#define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW) + +#define DOCTEST_BINARY_ASSERT(assert_type, lhs, rhs, comp) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #lhs ", " #rhs); \ + try { \ + _DOCTEST_RB.binary_assert(lhs, rhs); \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while(doctest::detail::always_false()) + +#define DOCTEST_UNARY_ASSERT(assert_type, val) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #val); \ + try { \ + _DOCTEST_RB.unary_assert(val); \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while(doctest::detail::always_false()) + +#define DOCTEST_WARN_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, lhs, rhs, eq) +#define DOCTEST_CHECK_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, lhs, rhs, eq) +#define DOCTEST_REQUIRE_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, lhs, rhs, eq) +#define DOCTEST_WARN_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_NE, lhs, rhs, ne) +#define DOCTEST_CHECK_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, lhs, rhs, ne) +#define DOCTEST_REQUIRE_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, lhs, rhs, ne) +#define DOCTEST_WARN_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GT, lhs, rhs, gt) +#define DOCTEST_CHECK_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, lhs, rhs, gt) +#define DOCTEST_REQUIRE_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, lhs, rhs, gt) +#define DOCTEST_WARN_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lhs, rhs, lt) +#define DOCTEST_CHECK_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lhs, rhs, lt) +#define DOCTEST_REQUIRE_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lhs, rhs, lt) +#define DOCTEST_WARN_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GE, lhs, rhs, ge) +#define DOCTEST_CHECK_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, lhs, rhs, ge) +#define DOCTEST_REQUIRE_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, lhs, rhs, ge) +#define DOCTEST_WARN_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LE, lhs, rhs, le) +#define DOCTEST_CHECK_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, lhs, rhs, le) +#define DOCTEST_REQUIRE_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, lhs, rhs, le) + +#define DOCTEST_WARN_UNARY(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, v) +#define DOCTEST_CHECK_UNARY(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, v) +#define DOCTEST_REQUIRE_UNARY(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, v) +#define DOCTEST_WARN_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, v) +#define DOCTEST_CHECK_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, v) +#define DOCTEST_REQUIRE_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, v) + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ + do { \ + int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ + doctest::detail::binaryAssertComparison::comparison>( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs, #rhs, lhs, \ + rhs); \ + if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ + } while(doctest::detail::always_false()) + +#define DOCTEST_FAST_UNARY_ASSERT(assert_type, val) \ + do { \ + int _DOCTEST_FAST_RES = doctest::detail::fast_unary_assert( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #val, val); \ + if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ + } while(doctest::detail::always_false()) + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ + doctest::detail::fast_binary_assert( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs, #rhs, lhs, rhs) + +#define DOCTEST_FAST_UNARY_ASSERT(assert_type, val) \ + doctest::detail::fast_unary_assert(doctest::detail::assertType::assert_type, __FILE__, \ + __LINE__, #val, val) + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_FAST_WARN_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, l, r, eq) +#define DOCTEST_FAST_CHECK_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, l, r, eq) +#define DOCTEST_FAST_REQUIRE_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, l, r, eq) +#define DOCTEST_FAST_WARN_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, l, r, ne) +#define DOCTEST_FAST_CHECK_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, l, r, ne) +#define DOCTEST_FAST_REQUIRE_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, l, r, ne) +#define DOCTEST_FAST_WARN_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, l, r, gt) +#define DOCTEST_FAST_CHECK_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, l, r, gt) +#define DOCTEST_FAST_REQUIRE_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, l, r, gt) +#define DOCTEST_FAST_WARN_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, l, r, lt) +#define DOCTEST_FAST_CHECK_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, l, r, lt) +#define DOCTEST_FAST_REQUIRE_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, l, r, lt) +#define DOCTEST_FAST_WARN_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, l, r, ge) +#define DOCTEST_FAST_CHECK_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, l, r, ge) +#define DOCTEST_FAST_REQUIRE_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, l, r, ge) +#define DOCTEST_FAST_WARN_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, l, r, le) +#define DOCTEST_FAST_CHECK_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, l, r, le) +#define DOCTEST_FAST_REQUIRE_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, l, r, le) + +#define DOCTEST_FAST_WARN_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, v) +#define DOCTEST_FAST_CHECK_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, v) +#define DOCTEST_FAST_REQUIRE_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, v) +#define DOCTEST_FAST_WARN_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, v) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, v) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(v) \ + DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, v) + +// ================================================================================================= +// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == +// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == +// ================================================================================================= +#else // DOCTEST_CONFIG_DISABLE + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace \ + { \ + template \ + struct der : base \ + { void f(); }; \ + } \ + template \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + template \ + static inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for subcases +#define DOCTEST_SUBCASE(name) + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_WARN(expr) ((void)0) +#define DOCTEST_WARN_FALSE(expr) ((void)0) +#define DOCTEST_WARN_THROWS(expr) ((void)0) +#define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_WARN_NOTHROW(expr) ((void)0) +#define DOCTEST_CHECK(expr) ((void)0) +#define DOCTEST_CHECK_FALSE(expr) ((void)0) +#define DOCTEST_CHECK_THROWS(expr) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) +#define DOCTEST_REQUIRE(expr) ((void)0) +#define DOCTEST_REQUIRE_FALSE(expr) ((void)0) +#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) + +#define DOCTEST_WARN_EQ(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_EQ(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_EQ(lhs, rhs) ((void)0) +#define DOCTEST_WARN_NE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_NE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_NE(lhs, rhs) ((void)0) +#define DOCTEST_WARN_GT(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_GT(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_GT(lhs, rhs) ((void)0) +#define DOCTEST_WARN_LT(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_LT(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_LT(lhs, rhs) ((void)0) +#define DOCTEST_WARN_GE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_GE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_GE(lhs, rhs) ((void)0) +#define DOCTEST_WARN_LE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_LE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_LE(lhs, rhs) ((void)0) + +#define DOCTEST_WARN_UNARY(val) ((void)0) +#define DOCTEST_CHECK_UNARY(val) ((void)0) +#define DOCTEST_REQUIRE_UNARY(val) ((void)0) +#define DOCTEST_WARN_UNARY_FALSE(val) ((void)0) +#define DOCTEST_CHECK_UNARY_FALSE(val) ((void)0) +#define DOCTEST_REQUIRE_UNARY_FALSE(val) ((void)0) + +#define DOCTEST_FAST_WARN_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_LE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_LE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_LE(lhs, rhs) ((void)0) + +#define DOCTEST_FAST_WARN_UNARY(val) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY(val) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY(val) ((void)0) +#define DOCTEST_FAST_WARN_UNARY_FALSE(val) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(val) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(val) ((void)0) + +#endif // DOCTEST_CONFIG_DISABLE + +// BDD style macros +// clang-format off +#define DOCTEST_SCENARIO(name) TEST_CASE(" Scenario: " name) +#define DOCTEST_GIVEN(name) SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) SUBCASE("And when: " name) +#define DOCTEST_THEN(name) SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) SUBCASE(" And: " name) +// clang-format on + +// == SHORT VERSIONS OF THE MACROS +#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) + +#define TEST_CASE DOCTEST_TEST_CASE +#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE +#define SUBCASE DOCTEST_SUBCASE +#define TEST_SUITE DOCTEST_TEST_SUITE +#define TEST_SUITE_END DOCTEST_TEST_SUITE_END +#define WARN DOCTEST_WARN +#define WARN_FALSE DOCTEST_WARN_FALSE +#define WARN_THROWS DOCTEST_WARN_THROWS +#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS +#define WARN_NOTHROW DOCTEST_WARN_NOTHROW +#define CHECK DOCTEST_CHECK +#define CHECK_FALSE DOCTEST_CHECK_FALSE +#define CHECK_THROWS DOCTEST_CHECK_THROWS +#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS +#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW +#define REQUIRE DOCTEST_REQUIRE +#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE +#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS +#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS +#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW + +#define SCENARIO DOCTEST_SCENARIO +#define GIVEN DOCTEST_GIVEN +#define WHEN DOCTEST_WHEN +#define AND_WHEN DOCTEST_AND_WHEN +#define THEN DOCTEST_THEN +#define AND_THEN DOCTEST_AND_THEN + +#define WARN_EQ DOCTEST_WARN_EQ +#define CHECK_EQ DOCTEST_CHECK_EQ +#define REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define WARN_NE DOCTEST_WARN_NE +#define CHECK_NE DOCTEST_CHECK_NE +#define REQUIRE_NE DOCTEST_REQUIRE_NE +#define WARN_GT DOCTEST_WARN_GT +#define CHECK_GT DOCTEST_CHECK_GT +#define REQUIRE_GT DOCTEST_REQUIRE_GT +#define WARN_LT DOCTEST_WARN_LT +#define CHECK_LT DOCTEST_CHECK_LT +#define REQUIRE_LT DOCTEST_REQUIRE_LT +#define WARN_GE DOCTEST_WARN_GE +#define CHECK_GE DOCTEST_CHECK_GE +#define REQUIRE_GE DOCTEST_REQUIRE_GE +#define WARN_LE DOCTEST_WARN_LE +#define CHECK_LE DOCTEST_CHECK_LE +#define REQUIRE_LE DOCTEST_REQUIRE_LE +#define WARN_UNARY DOCTEST_WARN_UNARY +#define CHECK_UNARY DOCTEST_CHECK_UNARY +#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ +#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ +#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ +#define FAST_WARN_NE DOCTEST_FAST_WARN_NE +#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE +#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE +#define FAST_WARN_GT DOCTEST_FAST_WARN_GT +#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT +#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT +#define FAST_WARN_LT DOCTEST_FAST_WARN_LT +#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT +#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT +#define FAST_WARN_GE DOCTEST_FAST_WARN_GE +#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE +#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE +#define FAST_WARN_LE DOCTEST_FAST_WARN_LE +#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE +#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE +#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY +#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY +#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY +#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE +#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE +#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE + +#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_TEST_SUITE_END(); + +#endif // DOCTEST_LIBRARY_INCLUDED + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic pop +#endif // > gcc 4.6 +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#ifndef DOCTEST_SINGLE_HEADER +#define DOCTEST_SINGLE_HEADER +#endif // DOCTEST_SINGLE_HEADER + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wmissing-variable-declarations" +#pragma clang diagnostic ignored "-Wswitch" +#pragma clang diagnostic ignored "-Wswitch-enum" +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#pragma clang diagnostic ignored "-Wmissing-noreturn" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic push +#endif // > gcc 4.6 +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Weffc++" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#pragma GCC diagnostic ignored "-Winline" +#pragma GCC diagnostic ignored "-Wswitch" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#pragma GCC diagnostic ignored "-Wswitch-default" +#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif // > gcc 4.6 +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7) +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif // > gcc 4.7 +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3) +#pragma GCC diagnostic ignored "-Wuseless-cast" +#endif // > gcc 5.3 +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) // The compiler encountered a deprecated declaration +#pragma warning(disable : 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +#pragma warning(disable : 4706) // assignment within conditional expression +#pragma warning(disable : 4512) // 'class' : assignment operator could not be generated +#pragma warning(disable : 4127) // conditional expression is constant +#endif // _MSC_VER + +#if defined(DOCTEST_CONFIG_IMPLEMENT) || defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) || \ + !defined(DOCTEST_SINGLE_HEADER) +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +#ifndef DOCTEST_SINGLE_HEADER +#include "doctest_fwd.h" +#endif // DOCTEST_SINGLE_HEADER + +#if defined(__clang__) && defined(DOCTEST_NO_CPP11_COMPAT) +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif // __clang__ && DOCTEST_NO_CPP11_COMPAT + +// snprintf() not in the C++98 standard +#ifdef _MSC_VER +#define DOCTEST_SNPRINTF _snprintf +#else +#define DOCTEST_SNPRINTF snprintf +#endif + +#define DOCTEST_LOG_START() \ + do { \ + if(!DOCTEST_GCS().hasLoggedCurrentTestStart) { \ + doctest::detail::logTestStart(DOCTEST_GCS().currentTest->m_name, \ + DOCTEST_GCS().currentTest->m_file, \ + DOCTEST_GCS().currentTest->m_line); \ + DOCTEST_GCS().hasLoggedCurrentTestStart = true; \ + } \ + } while(doctest::detail::always_false()) + +// required includes - will go only in one translation unit! +#include +#include +// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace doctest +{ +namespace detail +{ + // not using std::strlen() because of valgrind errors when optimizations are turned on + // 'Invalid read of size 4' when the test suite len (with '\0') is not a multiple of 4 + // for details see http://stackoverflow.com/questions/35671155 + size_t my_strlen(const char* in) { + const char* temp = in; + while(temp && *temp) + ++temp; + return temp - in; + } + + template + T my_max(const T& lhs, const T& rhs) { + return lhs > rhs ? lhs : rhs; + } + + // case insensitive strcmp + int stricmp(char const* a, char const* b) { + for(;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if(d != 0 || !*a) + return d; + } + } + + template + String fpToString(T value, int precision) { + std::ostringstream oss; + oss << std::setprecision(precision) << std::fixed << value; + std::string d = oss.str(); + size_t i = d.find_last_not_of('0'); + if(i != std::string::npos && i != d.size() - 1) { + if(d[i] == '.') + i++; + d = d.substr(0, i + 1); + } + return d.c_str(); + } + + struct Endianness + { + enum Arch + { + Big, + Little + }; + + static Arch which() { + union _ + { + int asInt; + char asChar[sizeof(int)]; + } u; + + u.asInt = 1; + return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little; + } + }; + + String rawMemoryToString(const void* object, unsigned size) { + // Reverse order for little endian architectures + int i = 0, end = static_cast(size), inc = 1; + if(Endianness::which() == Endianness::Little) { + i = end - 1; + end = inc = -1; + } + + unsigned char const* bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for(; i != end; i += inc) + os << std::setw(2) << static_cast(bytes[i]); + return os.str().c_str(); + } + + std::ostream* createStream() { return new std::ostringstream(); } + String getStreamResult(std::ostream* in) { + return static_cast(in)->str().c_str(); + } + void freeStream(std::ostream* in) { delete in; } + +#ifndef DOCTEST_CONFIG_DISABLE + + // this holds both parameters for the command line and runtime data for tests + struct ContextState : TestAccessibleContextState + { + // == parameters from the command line + + std::vector > filters; + + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_colors; // if output to the console should be colorized + bool no_path_in_filenames; // if the path to files should be removed from the output + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retreived + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + + // == data for the tests being ran + + int numAssertions; + int numFailedAssertions; + int numFailedAssertionsForCurrentTestcase; + + // stuff for subcases + std::set subcasesPassed; + std::set subcasesEnteredLevels; + std::vector subcasesStack; + int subcasesCurrentLevel; + bool subcasesHasSkipped; + + void resetRunData() { + numAssertions = 0; + numFailedAssertions = 0; + } + + ContextState() + : filters(6) // 6 different filters total + { + resetRunData(); + } + }; + + ContextState*& getContextState(); +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +String::String(const char* in) + : m_str(static_cast(malloc(detail::my_strlen(in) + 1))) { + if(in) + strcpy(m_str, in); + else + m_str[0] = '\0'; +} + +String::String(const String& other) + : m_str(0) { + copy(other); +} + +void String::copy(const String& other) { + if(m_str) + free(m_str); + m_str = static_cast(malloc(detail::my_strlen(other.m_str) + 1)); + strcpy(m_str, other.m_str); +} + +String::~String() { free(m_str); } + +String& String::operator=(const String& other) { + if(this != &other) + copy(other); + return *this; +} + +String String::operator+(const String& other) const { return String(m_str) += other; } + +String& String::operator+=(const String& other) { + using namespace detail; + if(other.m_str != 0) { + char* newStr = static_cast(malloc(my_strlen(m_str) + my_strlen(other.m_str) + 1)); + strcpy(newStr, m_str); + strcpy(newStr + my_strlen(m_str), other.m_str); + free(m_str); + m_str = newStr; + } + return *this; +} + +unsigned String::size() const { return m_str ? detail::my_strlen(m_str) : 0; } +unsigned String::length() const { return size(); } + +int String::compare(const char* other, bool no_case) const { + if(no_case) + return detail::stricmp(m_str, other); + return strcmp(m_str, other); +} + +int String::compare(const String& other, bool no_case) const { + if(no_case) + return detail::stricmp(m_str, other.m_str); + return strcmp(m_str, other.m_str); +} + +std::ostream& operator<<(std::ostream& stream, const String& in) { + stream << in.c_str(); + return stream; +} + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) + , m_scale(1.0) + , m_value(value) {} + +bool operator==(double lhs, Approx const& rhs) { + // Thanks to Richard Harris for his help refining this formula + return fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + detail::my_max(fabs(lhs), fabs(rhs.m_value))); +} + +String Approx::toString() const { return String("Approx( ") + doctest::toString(m_value) + " )"; } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(char* in) { return toString(static_cast(in)); } +String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(bool in) { return in ? "true" : "false"; } +String toString(float in) { return detail::fpToString(in, 5) + "f"; } +String toString(double in) { return detail::fpToString(in, 10); } +String toString(double long in) { return detail::fpToString(in, 15); } + +String toString(char in) { + char buf[64]; + sprintf(buf, "%d", in); + return buf; +} + +String toString(char unsigned in) { + char buf[64]; + sprintf(buf, "%ud", in); + return buf; +} + +String toString(int short in) { + char buf[64]; + sprintf(buf, "%d", in); + return buf; +} + +String toString(int short unsigned in) { + char buf[64]; + sprintf(buf, "%u", in); + return buf; +} + +String toString(int in) { + char buf[64]; + sprintf(buf, "%d", in); + return buf; +} + +String toString(int unsigned in) { + char buf[64]; + sprintf(buf, "%u", in); + return buf; +} + +String toString(int long in) { + char buf[64]; + sprintf(buf, "%ld", in); + return buf; +} + +String toString(int long unsigned in) { + char buf[64]; + sprintf(buf, "%lu", in); + return buf; +} + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG +String toString(int long long in) { + char buf[64]; + sprintf(buf, "%lld", in); + return buf; +} +String toString(int long long unsigned in) { + char buf[64]; + sprintf(buf, "%llu", in); + return buf; +} +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +String toString(std::nullptr_t) { return "nullptr"; } +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +} // namespace doctest + +#if defined(DOCTEST_CONFIG_DISABLE) +namespace doctest +{ +Context::Context(int, const char* const*) {} +Context::~Context() {} +void Context::applyCommandLine(int, const char* const*) {} +void Context::addFilter(const char*, const char*) {} +void Context::clearFilters() {} +void Context::setOption(const char*, int) {} +void Context::setOption(const char*, const char*) {} +bool Context::shouldExit() { return false; } +int Context::run() { return 0; } +} // namespace doctest +#else // DOCTEST_CONFIG_DISABLE + +#if !defined(DOCTEST_CONFIG_COLORS_NONE) +#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_CONFIG_COLORS_WINDOWS +#else // linux +#define DOCTEST_CONFIG_COLORS_ANSI +#endif // platform +#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI +#endif // DOCTEST_CONFIG_COLORS_NONE + +#define DOCTEST_PRINTF_COLORED(buffer, color) \ + do { \ + if(buffer[0] != 0) { \ + doctest::detail::Color col(color); \ + printf("%s", buffer); \ + } \ + } while(doctest::detail::always_false()) + +// the buffer size used for snprintf() calls +#if !defined(DOCTEST_SNPRINTF_BUFFER_LENGTH) +#define DOCTEST_SNPRINTF_BUFFER_LENGTH 1024 +#endif // DOCTEST_SNPRINTF_BUFFER_LENGTH + +#if defined(_MSC_VER) || defined(__MINGW32__) +#if defined(_MSC_VER) && _MSC_VER >= 1700 +#define DOCTEST_WINDOWS_SAL_IN_OPT _In_opt_ +#else // _MSC_VER +#define DOCTEST_WINDOWS_SAL_IN_OPT +#endif // _MSC_VER +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( + DOCTEST_WINDOWS_SAL_IN_OPT const char*); +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +#endif // _MSC_VER || __MINGW32__ + +#ifdef DOCTEST_CONFIG_COLORS_ANSI +#include +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif // WIN32_MEAN_AND_LEAN +#ifndef VC_EXTRA_LEAN +#define VC_EXTRA_LEAN +#endif // VC_EXTRA_LEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#include +#endif + +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + +namespace doctest +{ +namespace detail +{ + bool TestData::operator<(const TestData& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + return strcmp(m_file, other.m_file) < 0; + } + + const char* getAssertString(assertType::Enum val) { + switch(val) { + // clang-format off + case assertType::DT_WARN : return "WARN"; + case assertType::DT_CHECK : return "CHECK"; + case assertType::DT_REQUIRE : return "REQUIRE"; + + case assertType::DT_WARN_FALSE : return "WARN_FALSE"; + case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; + case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; + + case assertType::DT_WARN_THROWS : return "WARN_THROWS"; + case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; + case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; + + case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; + case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; + case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; + + case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; + case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; + case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; + + case assertType::DT_WARN_EQ : return "WARN_EQ"; + case assertType::DT_CHECK_EQ : return "CHECK_EQ"; + case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; + case assertType::DT_WARN_NE : return "WARN_NE"; + case assertType::DT_CHECK_NE : return "CHECK_NE"; + case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; + case assertType::DT_WARN_GT : return "WARN_GT"; + case assertType::DT_CHECK_GT : return "CHECK_GT"; + case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; + case assertType::DT_WARN_LT : return "WARN_LT"; + case assertType::DT_CHECK_LT : return "CHECK_LT"; + case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; + case assertType::DT_WARN_GE : return "WARN_GE"; + case assertType::DT_CHECK_GE : return "CHECK_GE"; + case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; + case assertType::DT_WARN_LE : return "WARN_LE"; + case assertType::DT_CHECK_LE : return "CHECK_LE"; + case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; + + case assertType::DT_WARN_UNARY : return "WARN_UNARY"; + case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; + case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; + case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; + case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; + case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; + + case assertType::DT_FAST_WARN_EQ : return "FAST_WARN_EQ"; + case assertType::DT_FAST_CHECK_EQ : return "FAST_CHECK_EQ"; + case assertType::DT_FAST_REQUIRE_EQ : return "FAST_REQUIRE_EQ"; + case assertType::DT_FAST_WARN_NE : return "FAST_WARN_NE"; + case assertType::DT_FAST_CHECK_NE : return "FAST_CHECK_NE"; + case assertType::DT_FAST_REQUIRE_NE : return "FAST_REQUIRE_NE"; + case assertType::DT_FAST_WARN_GT : return "FAST_WARN_GT"; + case assertType::DT_FAST_CHECK_GT : return "FAST_CHECK_GT"; + case assertType::DT_FAST_REQUIRE_GT : return "FAST_REQUIRE_GT"; + case assertType::DT_FAST_WARN_LT : return "FAST_WARN_LT"; + case assertType::DT_FAST_CHECK_LT : return "FAST_CHECK_LT"; + case assertType::DT_FAST_REQUIRE_LT : return "FAST_REQUIRE_LT"; + case assertType::DT_FAST_WARN_GE : return "FAST_WARN_GE"; + case assertType::DT_FAST_CHECK_GE : return "FAST_CHECK_GE"; + case assertType::DT_FAST_REQUIRE_GE : return "FAST_REQUIRE_GE"; + case assertType::DT_FAST_WARN_LE : return "FAST_WARN_LE"; + case assertType::DT_FAST_CHECK_LE : return "FAST_CHECK_LE"; + case assertType::DT_FAST_REQUIRE_LE : return "FAST_REQUIRE_LE"; + + case assertType::DT_FAST_WARN_UNARY : return "FAST_WARN_UNARY"; + case assertType::DT_FAST_CHECK_UNARY : return "FAST_CHECK_UNARY"; + case assertType::DT_FAST_REQUIRE_UNARY : return "FAST_REQUIRE_UNARY"; + case assertType::DT_FAST_WARN_UNARY_FALSE : return "FAST_WARN_UNARY_FALSE"; + case assertType::DT_FAST_CHECK_UNARY_FALSE : return "FAST_CHECK_UNARY_FALSE"; + case assertType::DT_FAST_REQUIRE_UNARY_FALSE: return "FAST_REQUIRE_UNARY_FALSE"; + // clang-format on + } + return ""; + } + + bool checkIfShouldThrow(assertType::Enum assert_type) { + if(assert_type & assertType::is_require) + return true; + + if((assert_type & assertType::is_check) && getContextState()->abort_after > 0) { + if(getContextState()->numFailedAssertions >= getContextState()->abort_after) + return true; + } + + return false; + } + void fastAssertThrowIfFlagSet(int flags) { + if(flags & assertAction::shouldthrow) + throwException(); + } + void throwException() { throw TestFailureException(); } + bool always_false() { return false; } + + // lowers ascii letters + char tolower(const char c) { return ((c >= 'A' && c <= 'Z') ? static_cast(c + 32) : c); } + + // matching of a string against a wildcard mask (case sensitivity configurable) taken from + // http://www.emoticode.net/c/simple-wildcard-string-compare-globbing-function.html + int wildcmp(const char* str, const char* wild, bool caseSensitive) { + const char* cp = 0; + const char* mp = 0; + + // rolled my own tolower() to not include more headers + while((*str) && (*wild != '*')) { + if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && + (*wild != '?')) { + return 0; + } + wild++; + str++; + } + + while(*str) { + if(*wild == '*') { + if(!*++wild) { + return 1; + } + mp = wild; + cp = str + 1; + } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || + (*wild == '?')) { + wild++; + str++; + } else { + wild = mp; + str = cp++; + } + } + + while(*wild == '*') { + wild++; + } + return !*wild; + } + + //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + //unsigned hashStr(unsigned const char* str) { + // unsigned long hash = 5381; + // char c; + // while((c = *str++)) + // hash = ((hash << 5) + hash) + c; // hash * 33 + c + // return hash; + //} + + // checks if the name matches any of the filters (and can be configured what to do when empty) + int matchesAny(const char* name, std::vector filters, int matchEmpty, + bool caseSensitive) { + if(filters.size() == 0 && matchEmpty) + return 1; + for(unsigned i = 0; i < filters.size(); ++i) + if(wildcmp(name, filters[i].c_str(), caseSensitive)) + return 1; + return 0; + } + + // the current ContextState with which tests are being executed + ContextState*& getContextState() { + static ContextState* data = 0; + return data; + } + + TestAccessibleContextState* getTestsContextState() { return getContextState(); } + + bool SubcaseSignature::operator<(const SubcaseSignature& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + if(strcmp(m_file, other.m_file) != 0) + return strcmp(m_file, other.m_file) < 0; + return strcmp(m_name, other.m_name) < 0; + } + + Subcase::Subcase(const char* name, const char* file, int line) + : m_signature(name, file, line) + , m_entered(false) { + ContextState* s = getContextState(); + + // if we have already completed it + if(s->subcasesPassed.count(m_signature) != 0) + return; + + // if a Subcase on the same level has already been entered + if(s->subcasesEnteredLevels.count(s->subcasesCurrentLevel) != 0) { + s->subcasesHasSkipped = true; + return; + } + + s->subcasesStack.push_back(*this); + if(s->hasLoggedCurrentTestStart) + logTestEnd(); + s->hasLoggedCurrentTestStart = false; + + s->subcasesEnteredLevels.insert(s->subcasesCurrentLevel++); + m_entered = true; + } + + Subcase::Subcase(const Subcase& other) + : m_signature(other.m_signature.m_name, other.m_signature.m_file, + other.m_signature.m_line) + , m_entered(other.m_entered) {} + + Subcase::~Subcase() { + if(m_entered) { + ContextState* s = getContextState(); + + s->subcasesCurrentLevel--; + // only mark the subcase as passed if no subcases have been skipped + if(s->subcasesHasSkipped == false) + s->subcasesPassed.insert(m_signature); + + if(s->subcasesStack.size() > 0) + s->subcasesStack.pop_back(); + if(s->hasLoggedCurrentTestStart) + logTestEnd(); + s->hasLoggedCurrentTestStart = false; + } + } + + // for sorting tests by file/line + int fileOrderComparator(const void* a, const void* b) { + const TestData* lhs = *static_cast(a); + const TestData* rhs = *static_cast(b); +#ifdef _MSC_VER + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + int res = stricmp(lhs->m_file, rhs->m_file); +#else // _MSC_VER + int res = strcmp(lhs->m_file, rhs->m_file); +#endif // _MSC_VER + if(res != 0) + return res; + return static_cast(lhs->m_line - rhs->m_line); + } + + // for sorting tests by suite/file/line + int suiteOrderComparator(const void* a, const void* b) { + const TestData* lhs = *static_cast(a); + const TestData* rhs = *static_cast(b); + + int res = strcmp(lhs->m_suite, rhs->m_suite); + if(res != 0) + return res; + return fileOrderComparator(a, b); + } + + // for sorting tests by name/suite/file/line + int nameOrderComparator(const void* a, const void* b) { + const TestData* lhs = *static_cast(a); + const TestData* rhs = *static_cast(b); + + int res = strcmp(lhs->m_name, rhs->m_name); + if(res != 0) + return res; + return suiteOrderComparator(a, b); + } + + // holds the current test suite + const char*& getCurrentTestSuite() { + static const char* data = 0; + return data; + } + + // sets the current test suite + int setTestSuiteName(const char* name) { + getCurrentTestSuite() = name; + return 0; + } + + // all the registered tests + std::set& getRegisteredTests() { + static std::set data; + return data; + } + + // used by the macros for registering tests + int regTest(funcType f, unsigned line, const char* file, const char* name) { + getRegisteredTests().insert(TestData(getCurrentTestSuite(), name, f, file, line)); + return 0; + } + + struct Color + { + enum Code + { + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White + }; + Color(Code code) { use(code); } + ~Color() { use(None); } + + void use(Code code); + + private: + Color(Color const& other); + }; + + void Color::use(Code +#ifndef DOCTEST_CONFIG_COLORS_NONE + code +#endif // DOCTEST_CONFIG_COLORS_NONE + ) { + ContextState* p = getContextState(); + if(p->no_colors) + return; +#ifdef DOCTEST_CONFIG_COLORS_ANSI + if(isatty(STDOUT_FILENO)) { + const char* col = ""; + // clang-format off + switch(code) { + case Color::Red: col = "[0;31m"; break; + case Color::Green: col = "[0;32m"; break; + case Color::Blue: col = "[0;34m"; break; + case Color::Cyan: col = "[0;36m"; break; + case Color::Yellow: col = "[0;33m"; break; + case Color::Grey: col = "[1;30m"; break; + case Color::LightGrey: col = "[0;37m"; break; + case Color::BrightRed: col = "[1;31m"; break; + case Color::BrightGreen: col = "[1;32m"; break; + case Color::BrightWhite: col = "[1;37m"; break; + case Color::Bright: // invalid + case Color::None: + case Color::White: + default: col = "[0m"; + } + // clang-format on + printf("\033%s", col); + } +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + static HANDLE stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE)); + static WORD originalForegroundAttributes; + static WORD originalBackgroundAttributes; + static bool attrsInitted = false; + if(!attrsInitted) { + attrsInitted = true; + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); + originalForegroundAttributes = + csbiInfo.wAttributes & + ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY); + originalBackgroundAttributes = + csbiInfo.wAttributes & + ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } + +#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(stdoutHandle, x | originalBackgroundAttributes) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(originalForegroundAttributes); + } +// clang-format on +#undef DOCTEST_SET_ATTR +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + } + + // this is needed because MSVC does not permit mixing 2 exception handling schemes in a function + int callTestFunc(funcType f) { + int res = EXIT_SUCCESS; + try { + f(); + if(getContextState()->numFailedAssertionsForCurrentTestcase) + res = EXIT_FAILURE; + } catch(const TestFailureException&) { res = EXIT_FAILURE; } catch(...) { + DOCTEST_LOG_START(); + logTestCrashed(); + res = EXIT_FAILURE; + } + return res; + } + + // depending on the current options this will remove the path of filenames + const char* fileForOutput(const char* file) { + if(getContextState()->no_path_in_filenames) { + const char* back = strrchr(file, '\\'); + const char* forward = strrchr(file, '/'); + if(back || forward) { + if(back > forward) + forward = back; + return forward + 1; + } + } + return file; + } + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + struct kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if(sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, 0, 0) != 0) { + fprintf(stderr, "\n** Call to sysctl failed - unable to determine if debugger is " + "active **\n\n"); + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } +#elif defined(_MSC_VER) || defined(__MINGW32__) + bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } +#else + bool isDebuggerActive() { return false; } +#endif // Platform + +#ifdef DOCTEST_PLATFORM_WINDOWS + void myOutputDebugString(const String& text) { ::OutputDebugStringA(text.c_str()); } +#else + // TODO: integration with XCode and other IDEs + void myOutputDebugString(const String&) {} +#endif // Platform + + const char* getSeparator() { + return "===============================================================================\n"; + } + + void printToDebugConsole(const String& text) { + if(isDebuggerActive()) + myOutputDebugString(text.c_str()); + } + + void addFailedAssert(assertType::Enum assert_type) { + if((assert_type & assertType::is_warn) == 0) { + getContextState()->numFailedAssertionsForCurrentTestcase++; + getContextState()->numFailedAssertions++; + } + } + + void logTestStart(const char* name, const char* file, unsigned line) { + const char* newLine = "\n"; + + char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)\n", fileForOutput(file), line); + + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), "%s\n", name); + + DOCTEST_PRINTF_COLORED(getSeparator(), Color::Yellow); + DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); + DOCTEST_PRINTF_COLORED(msg, Color::None); + + String subcaseStuff = ""; + std::vector& subcasesStack = getContextState()->subcasesStack; + for(unsigned i = 0; i < subcasesStack.size(); ++i) { + char subcase[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(subcase, DOCTEST_COUNTOF(loc), " %s\n", + subcasesStack[i].m_signature.m_name); + DOCTEST_PRINTF_COLORED(subcase, Color::None); + subcaseStuff += subcase; + } + + DOCTEST_PRINTF_COLORED(newLine, Color::None); + + printToDebugConsole(String(getSeparator()) + loc + msg + subcaseStuff.c_str() + newLine); + } + + void logTestEnd() {} + + void logTestCrashed() { + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), "TEST CASE FAILED! (threw exception)\n\n"); + + DOCTEST_PRINTF_COLORED(msg, Color::Red); + + printToDebugConsole(String(msg)); + } + + void logAssert(bool passed, const char* decomposition, bool threw, const char* expr, + assertType::Enum assert_type, const char* file, int line) { + char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); + + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + if(passed) + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); + else + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED! %s\n", + (threw ? "(threw exception)" : "")); + + char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n", + getAssertString(assert_type), expr); + + char info2[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + char info3[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + info2[0] = 0; + info3[0] = 0; + if(!threw) { + DOCTEST_SNPRINTF(info2, DOCTEST_COUNTOF(info2), "with expansion:\n"); + DOCTEST_SNPRINTF(info3, DOCTEST_COUNTOF(info3), " %s( %s )\n", + getAssertString(assert_type), decomposition); + } + + DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); + DOCTEST_PRINTF_COLORED(msg, passed ? Color::BrightGreen : Color::Red); + DOCTEST_PRINTF_COLORED(info1, Color::Cyan); + DOCTEST_PRINTF_COLORED(info2, Color::None); + DOCTEST_PRINTF_COLORED(info3, Color::Cyan); + DOCTEST_PRINTF_COLORED("\n", Color::None); + + printToDebugConsole(String(loc) + msg + info1 + info2 + info3 + "\n"); + } + + void logAssertThrows(bool threw, const char* expr, assertType::Enum assert_type, + const char* file, int line) { + char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); + + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + if(threw) + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); + else + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED!\n"); + + char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n\n", + getAssertString(assert_type), expr); + + DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); + DOCTEST_PRINTF_COLORED(msg, threw ? Color::BrightGreen : Color::Red); + DOCTEST_PRINTF_COLORED(info1, Color::Cyan); + + printToDebugConsole(String(loc) + msg + info1); + } + + void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const char* expr, + assertType::Enum assert_type, const char* file, int line) { + char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); + + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + if(threw_as) + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); + else + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED! %s\n", + (threw ? "(threw something else)" : "(didn't throw at all)")); + + char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s, %s )\n\n", + getAssertString(assert_type), expr, as); + + DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); + DOCTEST_PRINTF_COLORED(msg, threw_as ? Color::BrightGreen : Color::Red); + DOCTEST_PRINTF_COLORED(info1, Color::Cyan); + + printToDebugConsole(String(loc) + msg + info1); + } + + void logAssertNothrow(bool threw, const char* expr, assertType::Enum assert_type, + const char* file, int line) { + char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); + + char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + if(!threw) + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); + else + DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED!\n"); + + char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n\n", + getAssertString(assert_type), expr); + + DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); + DOCTEST_PRINTF_COLORED(msg, !threw ? Color::BrightGreen : Color::Red); + DOCTEST_PRINTF_COLORED(info1, Color::Cyan); + + printToDebugConsole(String(loc) + msg + info1); + } + + ResultBuilder::ResultBuilder(assertType::Enum assert_type, const char* file, int line, + const char* expr, const char* exception_type) + : m_assert_type(assert_type) + , m_file(file) + , m_line(line) + , m_expr(expr) + , m_exception_type(exception_type) + , m_threw(false) + , m_threw_as(false) + , m_failed(false) {} + + bool ResultBuilder::log() { + if((m_assert_type & assertType::is_warn) == 0) + DOCTEST_GCS().numAssertionsForCurrentTestcase++; + + if(m_assert_type & assertType::is_false) { + m_result.invert(); + m_failed = m_result; + } else if(m_assert_type & assertType::is_throws) { + m_failed = !m_threw; + } else if(m_assert_type & assertType::is_throws_as) { + m_failed = !m_threw_as; + } else if(m_assert_type & assertType::is_nothrow) { + m_failed = m_threw; + } else { + m_failed = m_result; + } + + if(m_failed || DOCTEST_GCS().success) { + DOCTEST_LOG_START(); + + if(m_assert_type & assertType::is_throws) { + logAssertThrows(m_threw, m_expr, m_assert_type, m_file, m_line); + } else if(m_assert_type & assertType::is_throws_as) { + logAssertThrowsAs(m_threw, m_threw_as, m_exception_type, m_expr, m_assert_type, + m_file, m_line); + } else if(m_assert_type & assertType::is_nothrow) { + logAssertNothrow(m_threw, m_expr, m_assert_type, m_file, m_line); + } else { + logAssert(m_result.m_passed, m_result.m_decomposition.c_str(), m_threw, m_expr, + m_assert_type, m_file, m_line); + } + } + + if(m_failed) { + addFailedAssert(m_assert_type); + if(isDebuggerActive() && !DOCTEST_GCS().no_breaks) + return true; // should break into the debugger + } + return false; + } + + void ResultBuilder::react() const { + if(m_failed && checkIfShouldThrow(m_assert_type)) + throwException(); + } + + // the implementation of parseFlag() + bool parseFlagImpl(int argc, const char* const* argv, const char* pattern) { + for(int i = argc - 1; i >= 0; --i) { + const char* temp = strstr(argv[i], pattern); + if(temp && my_strlen(temp) == my_strlen(pattern)) { + // eliminate strings in which the chars before the option are not '-' + bool noBadCharsFound = true; + while(temp != argv[i]) { + if(*--temp != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[i][0] == '-') + return true; + } + } + return false; + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + if(!parseFlagImpl(argc, argv, pattern)) + return parseFlagImpl(argc, argv, pattern + 3); // 3 for "dt-" + return true; +#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseFlagImpl(argc, argv, pattern); +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + } + + // the implementation of parseOption() + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String& res) { + for(int i = argc - 1; i >= 0; --i) { + const char* temp = strstr(argv[i], pattern); + if(temp) { + // eliminate matches in which the chars before the option are not '-' + bool noBadCharsFound = true; + const char* curr = argv[i]; + while(curr != temp) { + if(*curr++ != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[i][0] == '-') { + temp += my_strlen(pattern); + unsigned len = my_strlen(temp); + if(len) { + res = temp; + return true; + } + } + } + } + return false; + } + + // parses an option and returns the string after the '=' character + bool parseOption(int argc, const char* const* argv, const char* pattern, String& res, + const String& defaultVal = String()) { + res = defaultVal; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + if(!parseOptionImpl(argc, argv, pattern, res)) + return parseOptionImpl(argc, argv, pattern + 3, res); // 3 for "dt-" + return true; +#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, res); +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + } + + // parses a comma separated list of words after a pattern in one of the arguments in argv + bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, + std::vector& res) { + String filtersString; + if(parseOption(argc, argv, pattern, filtersString)) { + // tokenize with "," as a separator + char* pch = strtok(filtersString.c_str(), ","); // modifies the string + while(pch != 0) { + if(my_strlen(pch)) + res.push_back(pch); + pch = strtok(0, ","); // uses the strtok() internal state to go to the next token + } + return true; + } + return false; + } + + enum optionType + { + option_bool, + option_int + }; + + // parses an int/bool option from the command line + bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, + int& res) { + String parsedValue; + if(parseOption(argc, argv, pattern, parsedValue)) { + if(type == 0) { + // boolean + const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 + const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 + + // if the value matches any of the positive/negative possibilities + for(unsigned i = 0; i < 4; i++) { + if(parsedValue.compare(positive[i], true) == 0) { + res = 1; + return true; + } + if(parsedValue.compare(negative[i], true) == 0) { + res = 0; + return true; + } + } + } else { + // integer + int theInt = atoi(parsedValue.c_str()); + if(theInt != 0) { + res = theInt; + return true; + } + } + } + return false; + } + + void printVersion() { + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("doctest version is \"%s\"\n", DOCTEST_VERSION_STR); + } + + void printHelp() { + printVersion(); + DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("filter values: \"str1,str2,str3\" (comma separated strings)\n"); + DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("filters use wildcards for matching strings\n"); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("something passes a filter if any of the strings in a filter matches\n"); + DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"dt-\" PREFIX!!!\n"); + DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("Query flags - the program quits after them. Available:\n\n"); + printf(" -?, --help, -h prints this message\n"); + printf(" -v, --version prints the version\n"); + printf(" -c, --count prints the number of matching tests\n"); + printf(" -ltc, --list-test-cases lists all matching tests by name\n"); + printf(" -lts, --list-test-suites lists all matching test suites\n\n"); + // ==================================================================================== << 79 + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("The available / options/filters are:\n\n"); + printf(" -tc, --test-case= filters tests by their name\n"); + printf(" -tce, --test-case-exclude= filters OUT tests by their name\n"); + printf(" -sf, --source-file= filters tests by their file\n"); + printf(" -sfe, --source-file-exclude= filters OUT tests by their file\n"); + printf(" -ts, --test-suite= filters tests by their test suite\n"); + printf(" -tse, --test-suite-exclude= filters OUT tests by their test suite\n"); + printf(" -ob, --order-by= how the tests should be ordered\n"); + printf(" - by [file/suite/name/rand]\n"); + printf(" -rs, --rand-seed= seed for random ordering\n"); + printf(" -f, --first= the first test passing the filters to\n"); + printf(" execute - for range-based execution\n"); + printf(" -l, --last= the last test passing the filters to\n"); + printf(" execute - for range-based execution\n"); + printf(" -aa, --abort-after= stop after failed assertions\n\n"); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("Bool options - can be used like flags and true is assumed. Available:\n\n"); + printf(" -s, --success= include successful assertions in output\n"); + printf(" -cs, --case-sensitive= filters being treated as case sensitive\n"); + printf(" -e, --exit= exits after the tests finish\n"); + printf(" -nt, --no-throw= skips exceptions-related assert checks\n"); + printf(" -ne, --no-exitcode= returns (or exits) always with success\n"); + printf(" -nr, --no-run= skips all runtime doctest operations\n"); + printf(" -nc, --no-colors= disables colors in output\n"); + printf(" -nb, --no-breaks= disables breakpoints in debuggers\n"); + printf(" -npf, --no-path-filenames= only filenames and no paths in output\n\n"); + // ==================================================================================== << 79 + + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("for more information visit the project documentation\n\n"); + } +} // namespace detail + +Context::Context(int argc, const char* const* argv) + : p(new detail::ContextState) { + parseArgs(argc, argv, true); +} + +Context::~Context() { delete p; } + +void Context::applyCommandLine(int argc, const char* const* argv) { parseArgs(argc, argv); } + +// parses args +void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { + using namespace detail; + + // clang-format off + parseCommaSepArgs(argc, argv, "dt-source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, "dt-sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, "dt-source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, "dt-sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, "dt-test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, "dt-ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, "dt-test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, "dt-tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, "dt-test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, "dt-tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, "dt-test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, "dt-tce=", p->filters[5]); + // clang-format on + + int intRes = 0; + String strRes; + +#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), option_bool, intRes) || \ + parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), option_bool, intRes)) \ + p->var = !!intRes; \ + else if(parseFlag(argc, argv, #name) || parseFlag(argc, argv, #sname)) \ + p->var = 1; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), option_int, intRes) || \ + parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), option_int, intRes)) \ + p->var = intRes; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ + if(parseOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), strRes, default) || \ + parseOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), strRes, default) || \ + withDefaults) \ + p->var = strRes + + // clang-format off + DOCTEST_PARSE_STR_OPTION(dt-order-by, dt-ob, order_by, "file"); + DOCTEST_PARSE_INT_OPTION(dt-rand-seed, dt-rs, rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION(dt-first, dt-f, first, 1); + DOCTEST_PARSE_INT_OPTION(dt-last, dt-l, last, 0); + + DOCTEST_PARSE_INT_OPTION(dt-abort-after, dt-aa, abort_after, 0); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-success, dt-s, success, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-case-sensitive, dt-cs, case_sensitive, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-exit, dt-e, exit, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-throw, dt-nt, no_throw, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-exitcode, dt-ne, no_exitcode, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-run, dt-nr, no_run, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-colors, dt-nc, no_colors, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-breaks, dt-nb, no_breaks, 0); + DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-path-filenames, dt-npf, no_path_in_filenames, 0); +// clang-format on + +#undef DOCTEST_PARSE_STR_OPTION +#undef DOCTEST_PARSE_INT_OPTION +#undef DOCTEST_PARSE_AS_BOOL_OR_FLAG + + if(withDefaults) { + p->help = false; + p->version = false; + p->count = false; + p->list_test_cases = false; + p->list_test_suites = false; + } + if(parseFlag(argc, argv, "dt-help") || parseFlag(argc, argv, "dt-h") || + parseFlag(argc, argv, "dt-?")) { + p->help = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-version") || parseFlag(argc, argv, "dt-v")) { + p->version = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-count") || parseFlag(argc, argv, "dt-c")) { + p->count = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-list-test-cases") || parseFlag(argc, argv, "dt-ltc")) { + p->list_test_cases = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-list-test-suites") || parseFlag(argc, argv, "dt-lts")) { + p->list_test_suites = true; + p->exit = true; + } +} + +// allows the user to add procedurally to the filters from the command line +void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } + +// allows the user to clear all filters from the command line +void Context::clearFilters() { + for(unsigned i = 0; i < p->filters.size(); ++i) + p->filters[i].clear(); +} + +// allows the user to override procedurally the int/bool options from the command line +void Context::setOption(const char* option, int value) { + setOption(option, toString(value).c_str()); +} + +// allows the user to override procedurally the string options from the command line +void Context::setOption(const char* option, const char* value) { + String argv = String("-") + option + "=" + value; + const char* lvalue = argv.c_str(); + parseArgs(1, &lvalue); +} + +// users should query this in their main() and exit the program if true +bool Context::shouldExit() { return p->exit; } + +// the main function that does all the filtering and test running +int Context::run() { + using namespace detail; + + getContextState() = p; + p->resetRunData(); + + // handle version, help and no_run + if(p->no_run || p->version || p->help) { + if(p->version) + printVersion(); + if(p->help) + printHelp(); + + getContextState() = 0; + + return EXIT_SUCCESS; + } + + printVersion(); + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("run with \"--help\" for options\n"); + + unsigned i = 0; // counter used for loops - here for VC6 + + std::set& registeredTests = getRegisteredTests(); + + std::vector testArray; + for(std::set::iterator it = registeredTests.begin(); it != registeredTests.end(); + ++it) + testArray.push_back(&(*it)); + + // sort the collected records + if(testArray.size() > 0) { + if(p->order_by.compare("file", true) == 0) { + qsort(&testArray[0], testArray.size(), sizeof(TestData*), fileOrderComparator); + } else if(p->order_by.compare("suite", true) == 0) { + qsort(&testArray[0], testArray.size(), sizeof(TestData*), suiteOrderComparator); + } else if(p->order_by.compare("name", true) == 0) { + qsort(&testArray[0], testArray.size(), sizeof(TestData*), nameOrderComparator); + } else if(p->order_by.compare("rand", true) == 0) { + srand(p->rand_seed); + + // random_shuffle implementation + const TestData** first = &testArray[0]; + for(i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = rand() % (i + 1); + + const TestData* temp = first[i]; + + first[i] = first[idxToSwap]; + first[idxToSwap] = temp; + } + } + } + + if(p->list_test_cases) { + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("listing all test case names\n"); + } + + std::set testSuitesPassingFilters; + if(p->list_test_suites) { + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("listing all test suites\n"); + } + + unsigned numTestsPassingFilters = 0; + unsigned numFailed = 0; + // invoke the registered functions if they match the filter criteria (or just count them) + for(i = 0; i < testArray.size(); i++) { + const TestData& data = *testArray[i]; + if(!matchesAny(data.m_file, p->filters[0], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_file, p->filters[1], 0, p->case_sensitive)) + continue; + if(!matchesAny(data.m_suite, p->filters[2], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_suite, p->filters[3], 0, p->case_sensitive)) + continue; + if(!matchesAny(data.m_name, p->filters[4], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_name, p->filters[5], 0, p->case_sensitive)) + continue; + + numTestsPassingFilters++; + + // do not execute the test if we are to only count the number of filter passing tests + if(p->count) + continue; + + // print the name of the test and don't execute it + if(p->list_test_cases) { + printf("%s\n", data.m_name); + continue; + } + + // print the name of the test suite if not done already and don't execute it + if(p->list_test_suites) { + if(testSuitesPassingFilters.count(data.m_suite) == 0) { + printf("%s\n", data.m_suite); + testSuitesPassingFilters.insert(data.m_suite); + } + continue; + } + + // skip the test if it is not in the execution range + if((p->last < numTestsPassingFilters && p->first <= p->last) || + (p->first > numTestsPassingFilters)) + continue; + + // execute the test if it passes all the filtering + { +#ifdef _MSC_VER +//__try { +#endif // _MSC_VER + + p->currentTest = &data; + + // if logging successful tests - force the start log + p->hasLoggedCurrentTestStart = false; + if(p->success) + DOCTEST_LOG_START(); + + unsigned didFail = 0; + p->subcasesPassed.clear(); + do { + // reset the assertion state + p->numAssertionsForCurrentTestcase = 0; + p->numFailedAssertionsForCurrentTestcase = 0; + + // reset some of the fields for subcases (except for the set of fully passed ones) + p->subcasesHasSkipped = false; + p->subcasesCurrentLevel = 0; + p->subcasesEnteredLevels.clear(); + + // execute the test + didFail += callTestFunc(data.m_f); + p->numAssertions += p->numAssertionsForCurrentTestcase; + + // exit this loop if enough assertions have failed + if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) + p->subcasesHasSkipped = false; + + // if the start has been logged + if(p->hasLoggedCurrentTestStart) + logTestEnd(); + p->hasLoggedCurrentTestStart = false; + + } while(p->subcasesHasSkipped == true); + + if(didFail > 0) + numFailed++; + + // stop executing tests if enough assertions have failed + if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) + break; + +#ifdef _MSC_VER +//} __except(1) { +// printf("Unknown SEH exception caught!\n"); +// numFailed++; +//} +#endif // _MSC_VER + } + } + + DOCTEST_PRINTF_COLORED(getSeparator(), numFailed > 0 ? Color::Red : Color::Green); + if(p->count || p->list_test_cases || p->list_test_suites) { + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + printf("number of tests passing the current filters: %d\n", numTestsPassingFilters); + } else { + char buff[DOCTEST_SNPRINTF_BUFFER_LENGTH]; + + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "test cases: %4d", numTestsPassingFilters); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d passed", + numTestsPassingFilters - numFailed); + DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::None : Color::Green); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d failed", numFailed); + DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::Red : Color::None); + + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d skipped\n", + static_cast(testArray.size()) - numTestsPassingFilters); + DOCTEST_PRINTF_COLORED(buff, Color::None); + + DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); + + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "assertions: %4d", p->numAssertions); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d passed", + p->numAssertions - p->numFailedAssertions); + DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::None : Color::Green); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); + DOCTEST_PRINTF_COLORED(buff, Color::None); + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d failed", p->numFailedAssertions); + DOCTEST_PRINTF_COLORED(buff, p->numFailedAssertions > 0 ? Color::Red : Color::None); + + DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " |\n"); + DOCTEST_PRINTF_COLORED(buff, Color::None); + } + + // remove any coloring + DOCTEST_PRINTF_COLORED("", Color::None); + + getContextState() = 0; + + if(numFailed && !p->no_exitcode) + return EXIT_FAILURE; + return EXIT_SUCCESS; +} +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE +#endif // DOCTEST_LIBRARY_IMPLEMENTATION +#endif // DOCTEST_CONFIG_IMPLEMENT + +// == THIS SUPPLIES A MAIN FUNCTION AND SHOULD BE DONE ONLY IN ONE TRANSLATION UNIT +#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_MAIN_CONFIGURED) +#define DOCTEST_MAIN_CONFIGURED +int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +#endif // DOCTEST_MAIN_CONFIGURED + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // __clang__ + +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +#pragma GCC diagnostic pop +#endif // > gcc 4.6 +#endif // __GNUC__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER diff --git a/unittests/forward_list.cpp b/unittests/forward_list.cpp index cf87d6215..aefef2e0b 100644 --- a/unittests/forward_list.cpp +++ b/unittests/forward_list.cpp @@ -24,89 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "forward_list.hpp" -template -void test_forward_list() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::forward_list o_podforward_list(100); - for(auto & elem : o_podforward_list) - elem = random_value(gen); - - std::forward_list o_iserforward_list(100); - for(auto & elem : o_iserforward_list) - elem = StructInternalSerialize( random_value(gen), random_value(gen) ); - - std::forward_list o_isplforward_list(100); - for(auto & elem : o_isplforward_list) - elem = StructInternalSplit( random_value(gen), random_value(gen) ); - - std::forward_list o_eserforward_list(100); - for(auto & elem : o_eserforward_list) - elem = StructExternalSerialize( random_value(gen), random_value(gen) ); - - std::forward_list o_esplforward_list(100); - for(auto & elem : o_esplforward_list) - elem = StructExternalSplit( random_value(gen), random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); +TEST_SUITE("forward_list"); - oar(o_podforward_list); - oar(o_iserforward_list); - oar(o_isplforward_list); - oar(o_eserforward_list); - oar(o_esplforward_list); - } - - std::forward_list i_podforward_list; - std::forward_list i_iserforward_list; - std::forward_list i_isplforward_list; - std::forward_list i_eserforward_list; - std::forward_list i_esplforward_list; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podforward_list); - iar(i_iserforward_list); - iar(i_isplforward_list); - iar(i_eserforward_list); - iar(i_esplforward_list); - } - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podforward_list.begin(), i_podforward_list.end(), o_podforward_list.begin(), o_podforward_list.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserforward_list.begin(), i_iserforward_list.end(), o_iserforward_list.begin(), o_iserforward_list.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplforward_list.begin(), i_isplforward_list.end(), o_isplforward_list.begin(), o_isplforward_list.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserforward_list.begin(), i_eserforward_list.end(), o_eserforward_list.begin(), o_eserforward_list.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplforward_list.begin(), i_esplforward_list.end(), o_esplforward_list.begin(), o_esplforward_list.end()); - } -} - -BOOST_AUTO_TEST_CASE( binary_forward_list ) +TEST_CASE("binary_forward_list") { test_forward_list(); } -BOOST_AUTO_TEST_CASE( portable_binary_forward_list ) +TEST_CASE("portable_binary_forward_list") { test_forward_list(); } -BOOST_AUTO_TEST_CASE( xml_forward_list ) +TEST_CASE("xml_forward_list") { test_forward_list(); } -BOOST_AUTO_TEST_CASE( json_forward_list ) +TEST_CASE("json_forward_list") { test_forward_list(); } + +TEST_SUITE_END(); diff --git a/unittests/forward_list.hpp b/unittests/forward_list.hpp new file mode 100644 index 000000000..c0f568b23 --- /dev/null +++ b/unittests/forward_list.hpp @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_FORWARD_LIST_H_ +#define CEREAL_TEST_FORWARD_LIST_H_ +#include "common.hpp" + +template inline +void test_forward_list() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::forward_list o_podforward_list(100); + for(auto & elem : o_podforward_list) + elem = random_value(gen); + + std::forward_list o_iserforward_list(100); + for(auto & elem : o_iserforward_list) + elem = StructInternalSerialize( random_value(gen), random_value(gen) ); + + std::forward_list o_isplforward_list(100); + for(auto & elem : o_isplforward_list) + elem = StructInternalSplit( random_value(gen), random_value(gen) ); + + std::forward_list o_eserforward_list(100); + for(auto & elem : o_eserforward_list) + elem = StructExternalSerialize( random_value(gen), random_value(gen) ); + + std::forward_list o_esplforward_list(100); + for(auto & elem : o_esplforward_list) + elem = StructExternalSplit( random_value(gen), random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podforward_list); + oar(o_iserforward_list); + oar(o_isplforward_list); + oar(o_eserforward_list); + oar(o_esplforward_list); + } + + std::forward_list i_podforward_list; + std::forward_list i_iserforward_list; + std::forward_list i_isplforward_list; + std::forward_list i_eserforward_list; + std::forward_list i_esplforward_list; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podforward_list); + iar(i_iserforward_list); + iar(i_isplforward_list); + iar(i_eserforward_list); + iar(i_esplforward_list); + } + + check_collection(i_podforward_list, o_podforward_list ); + check_collection(i_iserforward_list, o_iserforward_list); + check_collection(i_isplforward_list, o_isplforward_list); + check_collection(i_eserforward_list, o_eserforward_list); + check_collection(i_esplforward_list, o_esplforward_list); + } +} + +#endif // CEREAL_TEST_FORWARD_LIST_H_ diff --git a/unittests/list.cpp b/unittests/list.cpp index 8f14fe9ee..099f5306d 100644 --- a/unittests/list.cpp +++ b/unittests/list.cpp @@ -24,90 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "list.hpp" -template -void test_list() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::list o_podlist(100); - for(auto & elem : o_podlist) - elem = random_value(gen); - - std::list o_iserlist(100); - for(auto & elem : o_iserlist) - elem = StructInternalSerialize( random_value(gen), random_value(gen) ); - - std::list o_ispllist(100); - for(auto & elem : o_ispllist) - elem = StructInternalSplit( random_value(gen), random_value(gen) ); - - std::list o_eserlist(100); - for(auto & elem : o_eserlist) - elem = StructExternalSerialize( random_value(gen), random_value(gen) ); - - std::list o_espllist(100); - for(auto & elem : o_espllist) - elem = StructExternalSplit( random_value(gen), random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podlist); - oar(o_iserlist); - oar(o_ispllist); - oar(o_eserlist); - oar(o_espllist); - } - - std::list i_podlist; - std::list i_iserlist; - std::list i_ispllist; - std::list i_eserlist; - std::list i_espllist; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podlist); - iar(i_iserlist); - iar(i_ispllist); - iar(i_eserlist); - iar(i_espllist); - } - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podlist.begin(), i_podlist.end(), o_podlist.begin(), o_podlist.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserlist.begin(), i_iserlist.end(), o_iserlist.begin(), o_iserlist.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_ispllist.begin(), i_ispllist.end(), o_ispllist.begin(), o_ispllist.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserlist.begin(), i_eserlist.end(), o_eserlist.begin(), o_eserlist.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_espllist.begin(), i_espllist.end(), o_espllist.begin(), o_espllist.end()); - } -} +TEST_SUITE("list"); -BOOST_AUTO_TEST_CASE( binary_list ) +TEST_CASE("binary_list") { test_list(); } -BOOST_AUTO_TEST_CASE( portable_binary_list ) +TEST_CASE("portable_binary_list") { test_list(); } -BOOST_AUTO_TEST_CASE( xml_list ) +TEST_CASE("xml_list") { test_list(); } -BOOST_AUTO_TEST_CASE( json_list ) +TEST_CASE("json_list") { test_list(); } +TEST_SUITE_END(); diff --git a/unittests/list.hpp b/unittests/list.hpp new file mode 100644 index 000000000..9e8a7dd05 --- /dev/null +++ b/unittests/list.hpp @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_LIST_H_ +#define CEREAL_TEST_LIST_H_ +#include "common.hpp" + +template inline +void test_list() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::list o_podlist(100); + for(auto & elem : o_podlist) + elem = random_value(gen); + + std::list o_iserlist(100); + for(auto & elem : o_iserlist) + elem = StructInternalSerialize( random_value(gen), random_value(gen) ); + + std::list o_ispllist(100); + for(auto & elem : o_ispllist) + elem = StructInternalSplit( random_value(gen), random_value(gen) ); + + std::list o_eserlist(100); + for(auto & elem : o_eserlist) + elem = StructExternalSerialize( random_value(gen), random_value(gen) ); + + std::list o_espllist(100); + for(auto & elem : o_espllist) + elem = StructExternalSplit( random_value(gen), random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podlist); + oar(o_iserlist); + oar(o_ispllist); + oar(o_eserlist); + oar(o_espllist); + } + + std::list i_podlist; + std::list i_iserlist; + std::list i_ispllist; + std::list i_eserlist; + std::list i_espllist; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podlist); + iar(i_iserlist); + iar(i_ispllist); + iar(i_eserlist); + iar(i_espllist); + } + + check_collection(i_podlist, o_podlist); + check_collection(i_iserlist, o_iserlist); + check_collection(i_ispllist, o_ispllist); + check_collection(i_eserlist, o_eserlist); + check_collection(i_espllist, o_espllist); + } +} + +#endif // CEREAL_TEST_LIST_H_ diff --git a/unittests/load_construct.cpp b/unittests/load_construct.cpp index 509ac8856..923e19aaa 100644 --- a/unittests/load_construct.cpp +++ b/unittests/load_construct.cpp @@ -24,255 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "load_construct.hpp" -struct OneLA -{ - OneLA( int xx ) : x( xx ) {} - - int x; - - template - void serialize( Archive & ar ) - { ar( x ); } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - int xx; - ar( xx ); - construct( xx ); - } - - bool operator==( OneLA const & other ) const - { return x == other.x; } -}; - -std::ostream& operator<<(std::ostream& os, OneLA const & s) -{ - os << "[" << s.x << "]"; - return os; -} - -struct OneLAVersioned -{ - OneLAVersioned( int xx ) : x( xx ), v() {} - OneLAVersioned( int xx, int vv ) : x( xx ), v( vv ) {} - - int x; - std::uint32_t v; - - template - void serialize( Archive & ar, const std::uint32_t version ) - { ar( x ); v = version; } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct, const std::uint32_t version ) - { - int xx; - ar( xx ); - construct( xx, version ); - } - - bool operator==( OneLAVersioned const & other ) const - { return x == other.x; } -}; - -std::ostream& operator<<(std::ostream& os, OneLAVersioned const & s) -{ - os << "[" << s.x << "]"; - return os; -} - -CEREAL_CLASS_VERSION( OneLAVersioned, 13 ) - -struct TwoLA -{ - TwoLA( int xx ) : x( xx ) {} - - int x; - - template - void serialize( Archive & ar ) - { ar( x ); } - - bool operator==( TwoLA const & other ) const - { return x == other.x; } -}; - -std::ostream& operator<<(std::ostream& os, TwoLA const & s) -{ - os << "[" << s.x << "]"; - return os; -} - -namespace cereal -{ - template <> - struct LoadAndConstruct - { - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - int xx; - ar( xx ); - construct( xx ); - } - }; -} - -struct TwoLAVersioned -{ - TwoLAVersioned( int xx ) : x( xx ), v() {} - TwoLAVersioned( int xx, int vv ) : x( xx ), v( vv ) {} - - int x; - std::uint32_t v; - - template - void serialize( Archive & ar, const std::uint32_t version ) - { ar( x ); v = version; } - - bool operator==( TwoLAVersioned const & other ) const - { return x == other.x; } -}; - -std::ostream& operator<<(std::ostream& os, TwoLAVersioned const & s) -{ - os << "[" << s.x << "]"; - return os; -} - -namespace cereal -{ - template <> - struct LoadAndConstruct - { - template - static void load_and_construct( Archive & ar, cereal::construct & construct, const std::uint32_t version ) - { - int xx; - ar( xx ); - construct( xx, version ); - } - }; -} - -CEREAL_CLASS_VERSION( TwoLAVersioned, 1 ) - -struct ThreeLA : std::enable_shared_from_this -{ - ThreeLA( int xx ) : x( xx ) {} - - int x; - - template - void serialize( Archive & ar ) - { ar( x ); } - - bool operator==( ThreeLA const & other ) const - { return x == other.x; } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - int xx; - ar( xx ); - construct( xx ); - } -}; - -std::ostream& operator<<(std::ostream& os, ThreeLA const & s) -{ - os << "[" << s.x << "]"; - return os; -} - -template -void test_memory_load_construct() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - auto o_shared1 = std::make_shared( random_value(gen) ); - auto o_shared2 = std::make_shared( random_value(gen) ); - std::unique_ptr o_unique1( new OneLA( random_value(gen) ) ); - std::unique_ptr o_unique2( new TwoLA( random_value(gen) ) ); - auto o_shared3 = std::make_shared( random_value(gen) ); - auto o_shared1v = std::make_shared( random_value(gen) ); - auto o_shared2v = std::make_shared( random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_shared1 ); - oar( o_shared2 ); - oar( o_unique1 ); - oar( o_unique2 ); - oar( o_shared3 ); - oar( o_shared1v ); - oar( o_shared2v ); - } - - o_shared3->shared_from_this(); // tests github issue #68 - - decltype(o_shared1) i_shared1; - decltype(o_shared2) i_shared2; - decltype(o_unique1) i_unique1; - decltype(o_unique2) i_unique2; - decltype(o_shared3) i_shared3; - decltype(o_shared1v) i_shared1v; - decltype(o_shared2v) i_shared2v; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_shared1 ); - iar( i_shared2 ); - iar( i_unique1 ); - iar( i_unique2 ); - iar( i_shared3 ); - iar( i_shared1v ); - iar( i_shared2v ); - } - - BOOST_CHECK_EQUAL( *o_shared1, *i_shared1 ); - BOOST_CHECK_EQUAL( *o_shared2, *i_shared2 ); - BOOST_CHECK_EQUAL( *o_unique1, *i_unique1 ); - BOOST_CHECK_EQUAL( *o_unique2, *i_unique2 ); - BOOST_CHECK_EQUAL( *o_shared3, *i_shared3 ); - BOOST_CHECK_EQUAL( *o_shared1v, *i_shared1v ); - BOOST_CHECK_EQUAL(i_shared1v->v, 13u); - BOOST_CHECK_EQUAL( *o_shared2v, *i_shared2v ); - BOOST_CHECK_EQUAL(i_shared2v->v, 1u); - - auto i_shared3_2 = i_shared3->shared_from_this(); - BOOST_CHECK_EQUAL( *o_shared3, *i_shared3_2 ); - } -} +TEST_SUITE("load_construct"); -BOOST_AUTO_TEST_CASE( binary_memory_load_construct ) +TEST_CASE("binary_memory_load_construct") { test_memory_load_construct(); } -BOOST_AUTO_TEST_CASE( portable_binary_memory_load_construct ) +TEST_CASE("portable_binary_memory_load_construct") { test_memory_load_construct(); } -BOOST_AUTO_TEST_CASE( xml_memory_load_construct ) +TEST_CASE("xml_memory_load_construct") { test_memory_load_construct(); } -BOOST_AUTO_TEST_CASE( json_memory_load_construct ) +TEST_CASE("json_memory_load_construct") { test_memory_load_construct(); } +TEST_SUITE_END(); diff --git a/unittests/load_construct.hpp b/unittests/load_construct.hpp new file mode 100644 index 000000000..97b37c1d4 --- /dev/null +++ b/unittests/load_construct.hpp @@ -0,0 +1,260 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_LOAD_CONSTRUCT_H_ +#define CEREAL_TEST_LOAD_CONSTRUCT_H_ +#include "common.hpp" + +struct OneLA +{ + OneLA( int xx ) : x( xx ) {} + + int x; + + template + void serialize( Archive & ar ) + { ar( x ); } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + int xx; + ar( xx ); + construct( xx ); + } + + bool operator==( OneLA const & other ) const + { return x == other.x; } +}; + +std::ostream& operator<<(std::ostream& os, OneLA const & s) +{ + os << "[" << s.x << "]"; + return os; +} + +struct OneLAVersioned +{ + OneLAVersioned( int xx ) : x( xx ), v() {} + OneLAVersioned( int xx, int vv ) : x( xx ), v( vv ) {} + + int x; + std::uint32_t v; + + template + void serialize( Archive & ar, const std::uint32_t version ) + { ar( x ); v = version; } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct, const std::uint32_t version ) + { + int xx; + ar( xx ); + construct( xx, version ); + } + + bool operator==( OneLAVersioned const & other ) const + { return x == other.x; } +}; + +std::ostream& operator<<(std::ostream& os, OneLAVersioned const & s) +{ + os << "[" << s.x << "]"; + return os; +} + +CEREAL_CLASS_VERSION( OneLAVersioned, 13 ) + +struct TwoLA +{ + TwoLA( int xx ) : x( xx ) {} + + int x; + + template + void serialize( Archive & ar ) + { ar( x ); } + + bool operator==( TwoLA const & other ) const + { return x == other.x; } +}; + +std::ostream& operator<<(std::ostream& os, TwoLA const & s) +{ + os << "[" << s.x << "]"; + return os; +} + +namespace cereal +{ + template <> + struct LoadAndConstruct + { + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + int xx; + ar( xx ); + construct( xx ); + } + }; +} + +struct TwoLAVersioned +{ + TwoLAVersioned( int xx ) : x( xx ), v() {} + TwoLAVersioned( int xx, int vv ) : x( xx ), v( vv ) {} + + int x; + std::uint32_t v; + + template + void serialize( Archive & ar, const std::uint32_t version ) + { ar( x ); v = version; } + + bool operator==( TwoLAVersioned const & other ) const + { return x == other.x; } +}; + +std::ostream& operator<<(std::ostream& os, TwoLAVersioned const & s) +{ + os << "[" << s.x << "]"; + return os; +} + +namespace cereal +{ + template <> + struct LoadAndConstruct + { + template + static void load_and_construct( Archive & ar, cereal::construct & construct, const std::uint32_t version ) + { + int xx; + ar( xx ); + construct( xx, version ); + } + }; +} + +CEREAL_CLASS_VERSION( TwoLAVersioned, 1 ) + +struct ThreeLA : std::enable_shared_from_this +{ + ThreeLA( int xx ) : x( xx ) {} + + int x; + + template + void serialize( Archive & ar ) + { ar( x ); } + + bool operator==( ThreeLA const & other ) const + { return x == other.x; } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + int xx; + ar( xx ); + construct( xx ); + } +}; + +std::ostream& operator<<(std::ostream& os, ThreeLA const & s) +{ + os << "[" << s.x << "]"; + return os; +} + +template +void test_memory_load_construct() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + auto o_shared1 = std::make_shared( random_value(gen) ); + auto o_shared2 = std::make_shared( random_value(gen) ); + std::unique_ptr o_unique1( new OneLA( random_value(gen) ) ); + std::unique_ptr o_unique2( new TwoLA( random_value(gen) ) ); + auto o_shared3 = std::make_shared( random_value(gen) ); + auto o_shared1v = std::make_shared( random_value(gen) ); + auto o_shared2v = std::make_shared( random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_shared1 ); + oar( o_shared2 ); + oar( o_unique1 ); + oar( o_unique2 ); + oar( o_shared3 ); + oar( o_shared1v ); + oar( o_shared2v ); + } + + o_shared3->shared_from_this(); // tests github issue #68 + + decltype(o_shared1) i_shared1; + decltype(o_shared2) i_shared2; + decltype(o_unique1) i_unique1; + decltype(o_unique2) i_unique2; + decltype(o_shared3) i_shared3; + decltype(o_shared1v) i_shared1v; + decltype(o_shared2v) i_shared2v; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_shared1 ); + iar( i_shared2 ); + iar( i_unique1 ); + iar( i_unique2 ); + iar( i_shared3 ); + iar( i_shared1v ); + iar( i_shared2v ); + } + + CHECK_EQ( *o_shared1, *i_shared1 ); + CHECK_EQ( *o_shared2, *i_shared2 ); + CHECK_EQ( *o_unique1, *i_unique1 ); + CHECK_EQ( *o_unique2, *i_unique2 ); + CHECK_EQ( *o_shared3, *i_shared3 ); + CHECK_EQ( *o_shared1v, *i_shared1v ); + CHECK_EQ(i_shared1v->v, 13u); + CHECK_EQ( *o_shared2v, *i_shared2v ); + CHECK_EQ(i_shared2v->v, 1u); + + auto i_shared3_2 = i_shared3->shared_from_this(); + CHECK_EQ( *o_shared3, *i_shared3_2 ); + } +} + +#endif // CEREAL_TEST_LOAD_CONSTRUCT_H_ diff --git a/unittests/map.cpp b/unittests/map.cpp index 90dc283f8..40e1b841b 100644 --- a/unittests/map.cpp +++ b/unittests/map.cpp @@ -24,183 +24,49 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "map.hpp" -template -void test_map() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::map> o_vectormap; - for(int j=0; j<10; ++j) - { - size_t id = random_value(gen); - for(int k=0; k<100; ++k) - o_vectormap[id].emplace_back(random_value(gen), random_value(gen)); - } - - std::map o_podmap; - for(int j=0; j<100; ++j) - o_podmap.insert({random_value(gen), random_value(gen)}); - - std::map o_isermap; - for(int j=0; j<100; ++j) - o_isermap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::map o_isplmap; - for(int j=0; j<100; ++j) - o_isplmap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::map o_esermap; - for(int j=0; j<100; ++j) - o_esermap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::map o_esplmap; - for(int j=0; j<100; ++j) - o_esplmap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_vectormap); - oar(o_podmap); - oar(o_isermap); - oar(o_isplmap); - oar(o_esermap); - oar(o_esplmap); - } - - std::map> i_vectormap; - std::map i_podmap; - std::map i_isermap; - std::map i_isplmap; - std::map i_esermap; - std::map i_esplmap; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_vectormap); - iar(i_podmap); - iar(i_isermap); - iar(i_isplmap); - iar(i_esermap); - iar(i_esplmap); - } - - BOOST_CHECK_EQUAL(i_vectormap.size(), o_vectormap.size()); - auto o_v_it = o_vectormap.begin(); - auto i_v_it = i_vectormap.begin(); - for(;o_v_it != o_vectormap.end(); ++o_v_it, ++i_v_it) - { - BOOST_CHECK_EQUAL(i_v_it->second.size(), o_v_it->second.size()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_v_it->second.begin(), i_v_it->second.end(), o_v_it->second.begin(), o_v_it->second.end()); - } - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podmap.begin(), i_podmap.end(), o_podmap.begin(), o_podmap.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isermap.begin(), i_isermap.end(), o_isermap.begin(), o_isermap.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplmap.begin(), i_isplmap.end(), o_isplmap.begin(), o_isplmap.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esermap.begin(), i_esermap.end(), o_esermap.begin(), o_esermap.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplmap.begin(), i_esplmap.end(), o_esplmap.begin(), o_esplmap.end()); - } -} - -template -void test_map_memory() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::map> o_uniqueptrMap; - std::map> o_sharedptrMap; - - for(int j=0; j<100; ++j) - { - #ifdef CEREAL_OLDER_GCC - o_uniqueptrMap.insert( std::make_pair(random_value(gen), std::unique_ptr( new int( random_value(gen) ) )) ); - o_sharedptrMap.insert( std::make_pair(random_value(gen), std::make_shared( random_value(gen) )) ); - #else // NOT CEREAL_OLDER_GCC - o_uniqueptrMap.emplace( random_value(gen), std::unique_ptr( new int( random_value(gen) ) ) ); - o_sharedptrMap.emplace( random_value(gen), std::make_shared( random_value(gen) ) ); - #endif // NOT CEREAL_OLDER_GCC - } - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_uniqueptrMap ); - oar( o_sharedptrMap ); - } +TEST_SUITE("map"); - decltype( o_uniqueptrMap ) i_uniqueptrMap; - decltype( o_sharedptrMap ) i_sharedptrMap; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_uniqueptrMap ); - iar( i_sharedptrMap ); - } - - BOOST_CHECK_EQUAL(o_sharedptrMap.size(), i_sharedptrMap.size()); - BOOST_CHECK_EQUAL(o_uniqueptrMap.size(), i_uniqueptrMap.size()); - - auto o_v_it = o_uniqueptrMap.begin(); - auto i_v_it = i_uniqueptrMap.begin(); - for(;o_v_it != o_uniqueptrMap.end(); ++o_v_it, ++i_v_it) - { - BOOST_CHECK_EQUAL(i_v_it->first, o_v_it->first); - BOOST_CHECK_EQUAL(*i_v_it->second, *o_v_it->second); - } - } -} - -BOOST_AUTO_TEST_CASE( binary_map ) +TEST_CASE("binary_map") { test_map(); } -BOOST_AUTO_TEST_CASE( portable_binary_map ) +TEST_CASE("portable_binary_map") { test_map(); } -BOOST_AUTO_TEST_CASE( xml_map ) +TEST_CASE("xml_map") { test_map(); } -BOOST_AUTO_TEST_CASE( json_map ) +TEST_CASE("json_map") { test_map(); } -BOOST_AUTO_TEST_CASE( binary_map_memory ) +TEST_CASE("binary_map_memory") { test_map_memory(); } -BOOST_AUTO_TEST_CASE( portable_binary_map_memory ) +TEST_CASE("portable_binary_map_memory") { test_map_memory(); } -BOOST_AUTO_TEST_CASE( xml_map_memory ) +TEST_CASE("xml_map_memory") { test_map_memory(); } -BOOST_AUTO_TEST_CASE( json_map_memory ) +TEST_CASE("json_map_memory") { test_map_memory(); } + +TEST_SUITE_END(); diff --git a/unittests/map.hpp b/unittests/map.hpp new file mode 100644 index 000000000..20b7c6222 --- /dev/null +++ b/unittests/map.hpp @@ -0,0 +1,169 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_MAP_H_ +#define CEREAL_TEST_MAP_H_ +#include "common.hpp" + +template inline +void test_map() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::map> o_vectormap; + for(int j=0; j<10; ++j) + { + size_t id = random_value(gen); + for(int k=0; k<100; ++k) + o_vectormap[id].emplace_back(random_value(gen), random_value(gen)); + } + + std::map o_podmap; + for(int j=0; j<100; ++j) + o_podmap.insert({random_value(gen), random_value(gen)}); + + std::map o_isermap; + for(int j=0; j<100; ++j) + o_isermap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::map o_isplmap; + for(int j=0; j<100; ++j) + o_isplmap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::map o_esermap; + for(int j=0; j<100; ++j) + o_esermap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::map o_esplmap; + for(int j=0; j<100; ++j) + o_esplmap.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_vectormap); + oar(o_podmap); + oar(o_isermap); + oar(o_isplmap); + oar(o_esermap); + oar(o_esplmap); + } + + std::map> i_vectormap; + std::map i_podmap; + std::map i_isermap; + std::map i_isplmap; + std::map i_esermap; + std::map i_esplmap; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_vectormap); + iar(i_podmap); + iar(i_isermap); + iar(i_isplmap); + iar(i_esermap); + iar(i_esplmap); + } + + CHECK_EQ(i_vectormap.size(), o_vectormap.size()); + auto o_v_it = o_vectormap.begin(); + auto i_v_it = i_vectormap.begin(); + for(;o_v_it != o_vectormap.end(); ++o_v_it, ++i_v_it) + { + CHECK_EQ(i_v_it->second.size(), o_v_it->second.size()); + check_collection(i_v_it->second, o_v_it->second); + } + + check_collection(i_podmap, o_podmap); + check_collection(i_isermap, o_isermap); + check_collection(i_isplmap, o_isplmap); + check_collection(i_esermap, o_esermap); + check_collection(i_esplmap, o_esplmap); + } +} + +template inline +void test_map_memory() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::map> o_uniqueptrMap; + std::map> o_sharedptrMap; + + for(int j=0; j<100; ++j) + { + #ifdef CEREAL_OLDER_GCC + o_uniqueptrMap.insert( std::make_pair(random_value(gen), std::unique_ptr( new int( random_value(gen) ) )) ); + o_sharedptrMap.insert( std::make_pair(random_value(gen), std::make_shared( random_value(gen) )) ); + #else // NOT CEREAL_OLDER_GCC + o_uniqueptrMap.emplace( random_value(gen), std::unique_ptr( new int( random_value(gen) ) ) ); + o_sharedptrMap.emplace( random_value(gen), std::make_shared( random_value(gen) ) ); + #endif // NOT CEREAL_OLDER_GCC + } + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_uniqueptrMap ); + oar( o_sharedptrMap ); + } + + decltype( o_uniqueptrMap ) i_uniqueptrMap; + decltype( o_sharedptrMap ) i_sharedptrMap; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_uniqueptrMap ); + iar( i_sharedptrMap ); + } + + CHECK_EQ(o_sharedptrMap.size(), i_sharedptrMap.size()); + CHECK_EQ(o_uniqueptrMap.size(), i_uniqueptrMap.size()); + + auto o_v_it = o_uniqueptrMap.begin(); + auto i_v_it = i_uniqueptrMap.begin(); + for(;o_v_it != o_uniqueptrMap.end(); ++o_v_it, ++i_v_it) + { + CHECK_EQ(i_v_it->first, o_v_it->first); + CHECK_EQ(*i_v_it->second, *o_v_it->second); + } + } +} + +#endif // CEREAL_TEST_MAP_H_ diff --git a/unittests/memory.cpp b/unittests/memory.cpp index 8a8641019..8c6259273 100644 --- a/unittests/memory.cpp +++ b/unittests/memory.cpp @@ -24,131 +24,49 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "memory.hpp" -template -void test_memory() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::shared_ptr o_xptr1 = std::make_shared(random_value(gen)); - std::shared_ptr o_xptr2 = o_xptr1; - std::shared_ptr o_yptr1 = std::make_shared(random_value(gen)); - std::shared_ptr o_yptr2 = o_yptr1; - std::shared_ptr o_nullptr1; - std::shared_ptr o_nullptr2; - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_xptr1, o_xptr2 ); - oar( o_yptr1, o_yptr2 ); - oar( o_nullptr1, o_nullptr2 ); - } - - std::shared_ptr i_xptr1; - std::shared_ptr i_xptr2; - std::shared_ptr i_yptr1; - std::shared_ptr i_yptr2; - std::shared_ptr i_nullptr1; - std::shared_ptr i_nullptr2; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_xptr1, i_xptr2); - iar( i_yptr1, i_yptr2); - iar( i_nullptr1, i_nullptr2 ); - } - - BOOST_CHECK_EQUAL(o_xptr1.get(), o_xptr2.get()); - BOOST_CHECK_EQUAL(i_xptr1.get(), i_xptr2.get()); - BOOST_CHECK_EQUAL(*i_xptr1, *i_xptr2); - - BOOST_CHECK_EQUAL(o_yptr1.get(), o_yptr2.get()); - BOOST_CHECK_EQUAL(i_yptr1.get(), i_yptr2.get()); - BOOST_CHECK_EQUAL(*i_yptr1, *i_yptr2); - BOOST_CHECK(!i_nullptr1); - BOOST_CHECK(!i_nullptr2); - } -} +TEST_SUITE("memory"); -BOOST_AUTO_TEST_CASE( binary_memory ) +TEST_CASE("binary_memory") { test_memory(); } -BOOST_AUTO_TEST_CASE( portable_binary_memory ) +TEST_CASE("portable_binary_memory") { test_memory(); } -BOOST_AUTO_TEST_CASE( xml_memory ) +TEST_CASE("xml_memory") { test_memory(); } -BOOST_AUTO_TEST_CASE( json_memory ) +TEST_CASE("json_memory") { test_memory(); } -class TestClass -{ - public: - TestClass(int v) : x(v) { } - int x; - - private: - friend class cereal::access; - TestClass() { }; - - template - void serialize(Archive & ar) { ar(x); } -}; - - -template -void test_default_construction() -{ - auto o_ptr = std::make_shared(1); - std::shared_ptr i_ptr; - - std::ostringstream os; - { - OArchive oar(os); - oar(o_ptr); - } - { - std::istringstream is(os.str()); - IArchive iar(is); - iar(i_ptr); - } - BOOST_CHECK_EQUAL(o_ptr->x, i_ptr->x); -} - -BOOST_AUTO_TEST_CASE( binary_default_construction ) +TEST_CASE("binary_default_construction") { test_default_construction(); } -BOOST_AUTO_TEST_CASE( portable_binary_default_construction ) +TEST_CASE("portable_binary_default_construction") { test_default_construction(); } -BOOST_AUTO_TEST_CASE( xml_default_construction ) +TEST_CASE("xml_default_construction") { test_default_construction(); } -BOOST_AUTO_TEST_CASE( json_default_construction ) +TEST_CASE("json_default_construction") { test_default_construction(); } + +TEST_SUITE_END(); diff --git a/unittests/memory.hpp b/unittests/memory.hpp new file mode 100644 index 000000000..19ec2bbd4 --- /dev/null +++ b/unittests/memory.hpp @@ -0,0 +1,116 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_MEMORY_H_ +#define CEREAL_TEST_MEMORY_H_ +#include "common.hpp" + +template inline +void test_memory() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::shared_ptr o_xptr1 = std::make_shared(random_value(gen)); + std::shared_ptr o_xptr2 = o_xptr1; + std::shared_ptr o_yptr1 = std::make_shared(random_value(gen)); + std::shared_ptr o_yptr2 = o_yptr1; + std::shared_ptr o_nullptr1; + std::shared_ptr o_nullptr2; + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_xptr1, o_xptr2 ); + oar( o_yptr1, o_yptr2 ); + oar( o_nullptr1, o_nullptr2 ); + } + + std::shared_ptr i_xptr1; + std::shared_ptr i_xptr2; + std::shared_ptr i_yptr1; + std::shared_ptr i_yptr2; + std::shared_ptr i_nullptr1; + std::shared_ptr i_nullptr2; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_xptr1, i_xptr2); + iar( i_yptr1, i_yptr2); + iar( i_nullptr1, i_nullptr2 ); + } + + CHECK_EQ(o_xptr1.get(), o_xptr2.get()); + CHECK_EQ(i_xptr1.get(), i_xptr2.get()); + CHECK_EQ(*i_xptr1, *i_xptr2); + + CHECK_EQ(o_yptr1.get(), o_yptr2.get()); + CHECK_EQ(i_yptr1.get(), i_yptr2.get()); + CHECK_EQ(*i_yptr1, *i_yptr2); + CHECK_UNARY_FALSE(i_nullptr1); + CHECK_UNARY_FALSE(i_nullptr2); + } +} + +class TestClass +{ + public: + TestClass(int v) : x(v) { } + int x; + + private: + friend class cereal::access; + TestClass() { }; + + template + void serialize(Archive & ar) { ar(x); } +}; + +template inline +void test_default_construction() +{ + auto o_ptr = std::make_shared(1); + std::shared_ptr i_ptr; + + std::ostringstream os; + { + OArchive oar(os); + oar(o_ptr); + } + { + std::istringstream is(os.str()); + IArchive iar(is); + iar(i_ptr); + } + CHECK_EQ(o_ptr->x, i_ptr->x); +} + +#endif // CEREAL_TEST_LOAD_CONSTRUCT_H_ diff --git a/unittests/memory_cycles.cpp b/unittests/memory_cycles.cpp index a98dd86ff..461decc59 100644 --- a/unittests/memory_cycles.cpp +++ b/unittests/memory_cycles.cpp @@ -24,138 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "memory_cycles.hpp" -struct MemoryCycle -{ - MemoryCycle() = default; - - MemoryCycle( int v ) : - value( v ) - { } - - int value; - std::weak_ptr ptr; - - bool operator==( MemoryCycle const & other ) const - { - return value == other.value && ptr.lock() == other.ptr.lock(); - } - - template - void serialize( Archive & ar ) - { - ar( value, ptr ); - } -}; - -std::ostream& operator<<(std::ostream& os, MemoryCycle const & s) -{ - os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]"; - return os; -} - -class MemoryCycleLoadAndConstruct -{ - public: - MemoryCycleLoadAndConstruct( int v ) : - value( v ) - { } - - MemoryCycleLoadAndConstruct( int v, - std::weak_ptr p ) : - value( v ), - ptr( p ) - { } - - bool operator==( MemoryCycleLoadAndConstruct const & other ) const - { - return value == other.value && ptr.lock() == other.ptr.lock(); - } - - template - void serialize( Archive & ar ) - { - ar( value, ptr ); - } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - int val; - std::weak_ptr p; - - ar( val, p ); - construct( val, p ); - } - - int value; - std::weak_ptr ptr; -}; - -std::ostream& operator<<(std::ostream& os, MemoryCycleLoadAndConstruct const & s) -{ - os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]"; - return os; -} - -template -void test_memory_cycles() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - auto o_ptr1 = std::make_shared( random_value(gen) ); - o_ptr1->ptr = o_ptr1; - auto o_ptr2 = std::make_shared( random_value(gen) ); - o_ptr2->ptr = o_ptr2; - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_ptr1 ); - oar( o_ptr2 ); - } - - decltype(o_ptr1) i_ptr1; - decltype(o_ptr2) i_ptr2; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_ptr1 ); - iar( i_ptr2 ); - } - - BOOST_CHECK_EQUAL( o_ptr1->value, i_ptr1->value ); - BOOST_CHECK_EQUAL( i_ptr1.get(), i_ptr1->ptr.lock().get() ); - BOOST_CHECK_EQUAL( o_ptr2->value, i_ptr2->value ); - BOOST_CHECK_EQUAL( i_ptr2.get(), i_ptr2->ptr.lock().get() ); - } -} +TEST_SUITE("memory_cycles"); -BOOST_AUTO_TEST_CASE( binary_memory_cycles ) +TEST_CASE("binary_memory_cycles") { test_memory_cycles(); } -BOOST_AUTO_TEST_CASE( portable_binary_memory_cycles ) +TEST_CASE("portable_binary_memory_cycles") { test_memory_cycles(); } -BOOST_AUTO_TEST_CASE( xml_memory_cycles ) +TEST_CASE("xml_memory_cycles") { test_memory_cycles(); } -BOOST_AUTO_TEST_CASE( json_memory_cycles ) +TEST_CASE("json_memory_cycles") { test_memory_cycles(); } +TEST_SUITE_END(); diff --git a/unittests/memory_cycles.hpp b/unittests/memory_cycles.hpp new file mode 100644 index 000000000..9009723ae --- /dev/null +++ b/unittests/memory_cycles.hpp @@ -0,0 +1,142 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_MEMORY_CYCLES_H_ +#define CEREAL_TEST_MEMORY_CYCLES_H_ +#include "common.hpp" + +struct MemoryCycle +{ + MemoryCycle() = default; + + MemoryCycle( int v ) : + value( v ) + { } + + int value; + std::weak_ptr ptr; + + bool operator==( MemoryCycle const & other ) const + { + return value == other.value && ptr.lock() == other.ptr.lock(); + } + + template + void serialize( Archive & ar ) + { + ar( value, ptr ); + } +}; + +std::ostream& operator<<(std::ostream& os, MemoryCycle const & s) +{ + os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]"; + return os; +} + +class MemoryCycleLoadAndConstruct +{ + public: + MemoryCycleLoadAndConstruct( int v ) : + value( v ) + { } + + MemoryCycleLoadAndConstruct( int v, + std::weak_ptr p ) : + value( v ), + ptr( p ) + { } + + bool operator==( MemoryCycleLoadAndConstruct const & other ) const + { + return value == other.value && ptr.lock() == other.ptr.lock(); + } + + template + void serialize( Archive & ar ) + { + ar( value, ptr ); + } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + int val; + std::weak_ptr p; + + ar( val, p ); + construct( val, p ); + } + + int value; + std::weak_ptr ptr; +}; + +std::ostream& operator<<(std::ostream& os, MemoryCycleLoadAndConstruct const & s) +{ + os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]"; + return os; +} + +template inline +void test_memory_cycles() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + auto o_ptr1 = std::make_shared( random_value(gen) ); + o_ptr1->ptr = o_ptr1; + auto o_ptr2 = std::make_shared( random_value(gen) ); + o_ptr2->ptr = o_ptr2; + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_ptr1 ); + oar( o_ptr2 ); + } + + decltype(o_ptr1) i_ptr1; + decltype(o_ptr2) i_ptr2; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_ptr1 ); + iar( i_ptr2 ); + } + + CHECK_EQ( o_ptr1->value, i_ptr1->value ); + CHECK_EQ( i_ptr1.get(), i_ptr1->ptr.lock().get() ); + CHECK_EQ( o_ptr2->value, i_ptr2->value ); + CHECK_EQ( i_ptr2.get(), i_ptr2->ptr.lock().get() ); + } +} +#endif // CEREAL_TEST_MEMORY_CYCLES_H_ diff --git a/unittests/multimap.cpp b/unittests/multimap.cpp index af8492d17..8df857e16 100644 --- a/unittests/multimap.cpp +++ b/unittests/multimap.cpp @@ -24,124 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "multimap.hpp" -template -void test_multimap() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::multimap o_podmultimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_podmultimap.insert({key, random_value(gen)}); - o_podmultimap.insert({key, random_value(gen)}); - } - - std::multimap o_isermultimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_isermultimap.insert({key, { random_value(gen), random_value(gen) }}); - o_isermultimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::multimap o_isplmultimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_isplmultimap.insert({key, { random_value(gen), random_value(gen) }}); - o_isplmultimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::multimap o_esermultimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_esermultimap.insert({key, { random_value(gen), random_value(gen) }}); - o_esermultimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::multimap o_esplmultimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_esplmultimap.insert({key, { random_value(gen), random_value(gen) }}); - o_esplmultimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podmultimap); - oar(o_isermultimap); - oar(o_isplmultimap); - oar(o_esermultimap); - oar(o_esplmultimap); - } - - std::multimap i_podmultimap; - std::multimap i_isermultimap; - std::multimap i_isplmultimap; - std::multimap i_esermultimap; - std::multimap i_esplmultimap; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podmultimap); - iar(i_isermultimap); - iar(i_isplmultimap); - iar(i_esermultimap); - iar(i_esplmultimap); - } - -#define MULTIMAP_CHECK(InMap, OutMap) \ - for( auto & pair : OutMap ) \ - { \ - auto const count = InMap.count( pair.first ); \ - BOOST_CHECK_EQUAL( count, OutMap.count( pair.first ) ); \ - auto find = InMap.find( pair.first ); \ - bool found = false; \ - for( size_t i = 0; i < count; ++i, ++find ) \ - found |= find->second == pair.second; \ - BOOST_CHECK( found ); \ - } - - MULTIMAP_CHECK( i_podmultimap, o_podmultimap ); - MULTIMAP_CHECK( i_isermultimap, o_isermultimap ); - MULTIMAP_CHECK( i_isplmultimap, o_isplmultimap ); - MULTIMAP_CHECK( i_esermultimap, o_esermultimap ); - MULTIMAP_CHECK( i_esplmultimap, o_esplmultimap ); - -#undef MULTIMAP_CHECK - } -} +TEST_SUITE("multimap"); -BOOST_AUTO_TEST_CASE( binary_multimap ) +TEST_CASE("binary_multimap") { test_multimap(); } -BOOST_AUTO_TEST_CASE( portable_binary_multimap ) +TEST_CASE("portable_binary_multimap") { test_multimap(); } -BOOST_AUTO_TEST_CASE( xml_multimap ) +TEST_CASE("xml_multimap") { test_multimap(); } -BOOST_AUTO_TEST_CASE( json_multimap ) +TEST_CASE("json_multimap") { test_multimap(); } +TEST_SUITE_END(); diff --git a/unittests/multimap.hpp b/unittests/multimap.hpp new file mode 100644 index 000000000..142676942 --- /dev/null +++ b/unittests/multimap.hpp @@ -0,0 +1,129 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_MULTIMAP_H_ +#define CEREAL_TEST_MULTIMAP_H_ +#include "common.hpp" + +template inline +void test_multimap() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::multimap o_podmultimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_podmultimap.insert({key, random_value(gen)}); + o_podmultimap.insert({key, random_value(gen)}); + } + + std::multimap o_isermultimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_isermultimap.insert({key, { random_value(gen), random_value(gen) }}); + o_isermultimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::multimap o_isplmultimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_isplmultimap.insert({key, { random_value(gen), random_value(gen) }}); + o_isplmultimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::multimap o_esermultimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_esermultimap.insert({key, { random_value(gen), random_value(gen) }}); + o_esermultimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::multimap o_esplmultimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_esplmultimap.insert({key, { random_value(gen), random_value(gen) }}); + o_esplmultimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podmultimap); + oar(o_isermultimap); + oar(o_isplmultimap); + oar(o_esermultimap); + oar(o_esplmultimap); + } + + std::multimap i_podmultimap; + std::multimap i_isermultimap; + std::multimap i_isplmultimap; + std::multimap i_esermultimap; + std::multimap i_esplmultimap; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podmultimap); + iar(i_isermultimap); + iar(i_isplmultimap); + iar(i_esermultimap); + iar(i_esplmultimap); + } + +#define MULTIMAP_CHECK(InMap, OutMap) \ + for( auto & pair : OutMap ) \ + { \ + auto const count = InMap.count( pair.first ); \ + CHECK_EQ( count, OutMap.count( pair.first ) ); \ + auto find = InMap.find( pair.first ); \ + bool found = false; \ + for( size_t i = 0; i < count; ++i, ++find ) \ + found |= find->second == pair.second; \ + CHECK_UNARY( found ); \ + } + + MULTIMAP_CHECK( i_podmultimap, o_podmultimap ); + MULTIMAP_CHECK( i_isermultimap, o_isermultimap ); + MULTIMAP_CHECK( i_isplmultimap, o_isplmultimap ); + MULTIMAP_CHECK( i_esermultimap, o_esermultimap ); + MULTIMAP_CHECK( i_esplmultimap, o_esplmultimap ); + +#undef MULTIMAP_CHECK + } +} + +#endif // CEREAL_TEST_MULTIMAP_H_ diff --git a/unittests/multiset.cpp b/unittests/multiset.cpp index 206c69fb2..de53d2a24 100644 --- a/unittests/multiset.cpp +++ b/unittests/multiset.cpp @@ -24,130 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "multiset.hpp" -template -void test_multiset() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::multiset o_podmultiset; - for(int j=0; j<100; ++j) - { - int value = random_value(gen); - o_podmultiset.insert(value); - o_podmultiset.insert(value); - } - - std::multiset o_isermultiset; - for(int j=0; j<100; ++j) - { - StructInternalSerialize value = { random_value(gen), random_value(gen) }; - o_isermultiset.insert(value); - o_isermultiset.insert(value); - } - - std::multiset o_isplmultiset; - for(int j=0; j<100; ++j) - { - StructInternalSplit value = { random_value(gen), random_value(gen) }; - o_isplmultiset.insert(value); - o_isplmultiset.insert(value); - } - - std::multiset o_esermultiset; - for(int j=0; j<100; ++j) - { - StructExternalSerialize value = { random_value(gen), random_value(gen) }; - o_esermultiset.insert(value); - o_esermultiset.insert(value); - } - - std::multiset o_esplmultiset; - for(int j=0; j<100; ++j) - { - StructExternalSplit value = { random_value(gen), random_value(gen) }; - o_esplmultiset.insert(value); - o_esplmultiset.insert(value); - } - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podmultiset); - oar(o_isermultiset); - oar(o_isplmultiset); - oar(o_esermultiset); - oar(o_esplmultiset); - } - - std::multiset i_podmultiset; - std::multiset i_isermultiset; - std::multiset i_isplmultiset; - std::multiset i_esermultiset; - std::multiset i_esplmultiset; +TEST_SUITE("multiset"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podmultiset); - iar(i_isermultiset); - iar(i_isplmultiset); - iar(i_esermultiset); - iar(i_esplmultiset); - } - - for(auto const & p : i_podmultiset) - { - BOOST_CHECK_EQUAL(o_podmultiset.count(p), i_podmultiset.count(p)); - } - - for(auto const & p : i_isermultiset) - { - BOOST_CHECK_EQUAL(o_isermultiset.count(p), i_isermultiset.count(p)); - } - - for(auto const & p : i_isplmultiset) - { - BOOST_CHECK_EQUAL(o_isplmultiset.count(p), i_isplmultiset.count(p)); - } - - for(auto const & p : i_esermultiset) - { - BOOST_CHECK_EQUAL(o_esermultiset.count(p), i_esermultiset.count(p)); - } - - for(auto const & p : i_esplmultiset) - { - BOOST_CHECK_EQUAL(o_esplmultiset.count(p), i_esplmultiset.count(p)); - } - } -} - -BOOST_AUTO_TEST_CASE( binary_multiset ) +TEST_CASE("binary_multiset") { test_multiset(); } -BOOST_AUTO_TEST_CASE( portable_binary_multiset ) +TEST_CASE("portable_binary_multiset") { test_multiset(); } -BOOST_AUTO_TEST_CASE( xml_multiset ) +TEST_CASE("xml_multiset") { test_multiset(); } -BOOST_AUTO_TEST_CASE( json_multiset ) +TEST_CASE("json_multiset") { test_multiset(); } - +TEST_SUITE_END(); diff --git a/unittests/multiset.hpp b/unittests/multiset.hpp new file mode 100644 index 000000000..89ad7a1e0 --- /dev/null +++ b/unittests/multiset.hpp @@ -0,0 +1,134 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_MULTISET_H_ +#define CEREAL_TEST_MULTISET_H_ +#include "common.hpp" + +template inline +void test_multiset() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::multiset o_podmultiset; + for(int j=0; j<100; ++j) + { + int value = random_value(gen); + o_podmultiset.insert(value); + o_podmultiset.insert(value); + } + + std::multiset o_isermultiset; + for(int j=0; j<100; ++j) + { + StructInternalSerialize value = { random_value(gen), random_value(gen) }; + o_isermultiset.insert(value); + o_isermultiset.insert(value); + } + + std::multiset o_isplmultiset; + for(int j=0; j<100; ++j) + { + StructInternalSplit value = { random_value(gen), random_value(gen) }; + o_isplmultiset.insert(value); + o_isplmultiset.insert(value); + } + + std::multiset o_esermultiset; + for(int j=0; j<100; ++j) + { + StructExternalSerialize value = { random_value(gen), random_value(gen) }; + o_esermultiset.insert(value); + o_esermultiset.insert(value); + } + + std::multiset o_esplmultiset; + for(int j=0; j<100; ++j) + { + StructExternalSplit value = { random_value(gen), random_value(gen) }; + o_esplmultiset.insert(value); + o_esplmultiset.insert(value); + } + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podmultiset); + oar(o_isermultiset); + oar(o_isplmultiset); + oar(o_esermultiset); + oar(o_esplmultiset); + } + + std::multiset i_podmultiset; + std::multiset i_isermultiset; + std::multiset i_isplmultiset; + std::multiset i_esermultiset; + std::multiset i_esplmultiset; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podmultiset); + iar(i_isermultiset); + iar(i_isplmultiset); + iar(i_esermultiset); + iar(i_esplmultiset); + } + + for(auto const & p : i_podmultiset) + { + CHECK_EQ(o_podmultiset.count(p), i_podmultiset.count(p)); + } + + for(auto const & p : i_isermultiset) + { + CHECK_EQ(o_isermultiset.count(p), i_isermultiset.count(p)); + } + + for(auto const & p : i_isplmultiset) + { + CHECK_EQ(o_isplmultiset.count(p), i_isplmultiset.count(p)); + } + + for(auto const & p : i_esermultiset) + { + CHECK_EQ(o_esermultiset.count(p), i_esermultiset.count(p)); + } + + for(auto const & p : i_esplmultiset) + { + CHECK_EQ(o_esplmultiset.count(p), i_esplmultiset.count(p)); + } + } +} + +#endif // CEREAL_TEST_MULTISET_H_ diff --git a/unittests/pair.cpp b/unittests/pair.cpp index 4e1e61a3c..063237bff 100644 --- a/unittests/pair.cpp +++ b/unittests/pair.cpp @@ -24,86 +24,28 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "pair.hpp" -template -void test_pair() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rng = [&](){ return random_value(gen); }; - - for(int ii=0; ii<100; ++ii) - { - std::pair o_podpair = {rng(), rng()}; - std::pair o_iserpair = {{rng(), rng()}, {rng(), rng()}}; - std::pair o_isplpair = {{rng(), rng()}, {rng(), rng()}}; - std::pair o_eserpair = {{rng(), rng()}, {rng(), rng()}}; - std::pair o_esplpair = {{rng(), rng()}, {rng(), rng()}}; - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podpair); - oar(o_iserpair); - oar(o_isplpair); - oar(o_eserpair); - oar(o_esplpair); - } - - std::pair i_podpair; - std::pair i_iserpair; - std::pair i_isplpair; - std::pair i_eserpair; - std::pair i_esplpair; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podpair); - iar(i_iserpair); - iar(i_isplpair); - iar(i_eserpair); - iar(i_esplpair); - } - - BOOST_CHECK_EQUAL( i_podpair.first, o_podpair.first ); - BOOST_CHECK_EQUAL( i_podpair.second, o_podpair.second ); - - BOOST_CHECK_EQUAL( i_iserpair.first, o_iserpair.first ); - BOOST_CHECK_EQUAL( i_iserpair.second, o_iserpair.second ); - - BOOST_CHECK_EQUAL( i_isplpair.first, o_isplpair.first ); - BOOST_CHECK_EQUAL( i_isplpair.second, o_isplpair.second ); - - BOOST_CHECK_EQUAL( i_eserpair.first, o_eserpair.first ); - BOOST_CHECK_EQUAL( i_eserpair.second, o_eserpair.second ); - - BOOST_CHECK_EQUAL( i_esplpair.first, o_esplpair.first ); - BOOST_CHECK_EQUAL( i_esplpair.second, o_esplpair.second ); - } -} +TEST_SUITE("pair"); -BOOST_AUTO_TEST_CASE( binary_pair ) +TEST_CASE("binary_pair") { test_pair(); } -BOOST_AUTO_TEST_CASE( portable_binary_pair ) +TEST_CASE("portable_binary_pair") { test_pair(); } -BOOST_AUTO_TEST_CASE( xml_pair ) +TEST_CASE("xml_pair") { test_pair(); } -BOOST_AUTO_TEST_CASE( json_pair ) +TEST_CASE("json_pair") { test_pair(); } +TEST_SUITE_END(); diff --git a/unittests/pair.hpp b/unittests/pair.hpp new file mode 100644 index 000000000..fe6093178 --- /dev/null +++ b/unittests/pair.hpp @@ -0,0 +1,92 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_PAIR_H_ +#define CEREAL_TEST_PAIR_H_ +#include "common.hpp" + +template inline +void test_pair() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rng = [&](){ return random_value(gen); }; + + for(int ii=0; ii<100; ++ii) + { + std::pair o_podpair = {rng(), rng()}; + std::pair o_iserpair = {{rng(), rng()}, {rng(), rng()}}; + std::pair o_isplpair = {{rng(), rng()}, {rng(), rng()}}; + std::pair o_eserpair = {{rng(), rng()}, {rng(), rng()}}; + std::pair o_esplpair = {{rng(), rng()}, {rng(), rng()}}; + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podpair); + oar(o_iserpair); + oar(o_isplpair); + oar(o_eserpair); + oar(o_esplpair); + } + + std::pair i_podpair; + std::pair i_iserpair; + std::pair i_isplpair; + std::pair i_eserpair; + std::pair i_esplpair; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podpair); + iar(i_iserpair); + iar(i_isplpair); + iar(i_eserpair); + iar(i_esplpair); + } + + CHECK_EQ( i_podpair.first, o_podpair.first ); + CHECK_EQ( i_podpair.second, o_podpair.second ); + + CHECK_EQ( i_iserpair.first, o_iserpair.first ); + CHECK_EQ( i_iserpair.second, o_iserpair.second ); + + CHECK_EQ( i_isplpair.first, o_isplpair.first ); + CHECK_EQ( i_isplpair.second, o_isplpair.second ); + + CHECK_EQ( i_eserpair.first, o_eserpair.first ); + CHECK_EQ( i_eserpair.second, o_eserpair.second ); + + CHECK_EQ( i_esplpair.first, o_esplpair.first ); + CHECK_EQ( i_esplpair.second, o_esplpair.second ); + } +} + +#endif // CEREAL_TEST_PAIR_H_ diff --git a/unittests/pod.cpp b/unittests/pod.cpp index 4fe5ac81a..b2450e7b4 100644 --- a/unittests/pod.cpp +++ b/unittests/pod.cpp @@ -24,141 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "pod.hpp" -template -void test_pod() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(size_t i=0; i<100; ++i) - { - bool const o_bool = random_value(gen) % 2 ? true : false; - char const o_char = random_value(gen); - unsigned char const o_uchar = random_value(gen); - uint8_t const o_uint8 = random_value(gen); - int8_t const o_int8 = random_value(gen); - uint16_t const o_uint16 = random_value(gen); - int16_t const o_int16 = random_value(gen); - uint32_t const o_uint32 = random_value(gen); - int32_t const o_int32 = random_value(gen); - uint64_t const o_uint64 = random_value(gen); - int64_t const o_int64 = random_value(gen); - float const o_float = random_value(gen); - double const o_double = random_value(gen); - - long double const o_long_double = random_value(gen); - long const o_long = random_value(gen); - unsigned long const o_ulong = random_value(gen); - long long const o_long_long = random_value(gen); - unsigned long long const o_ulong_long = random_value(gen); - - std::ostringstream os; - { - OArchive oar(os); - oar(o_bool); - oar(o_char); - oar(o_uchar); - oar(o_uint8); - oar(o_int8); - oar(o_uint16); - oar(o_int16); - oar(o_uint32); - oar(o_int32); - oar(o_uint64); - oar(o_int64); - oar(o_float); - oar(o_double); - oar(o_long_double); - oar(o_long); - oar(o_ulong); - oar(o_long_long); - oar(o_ulong_long); - } - - bool i_bool = false; - char i_char = 0; - unsigned char i_uchar = 0; - uint8_t i_uint8 = 0; - int8_t i_int8 = 0; - uint16_t i_uint16 = 0; - int16_t i_int16 = 0; - uint32_t i_uint32 = 0; - int32_t i_int32 = 0; - uint64_t i_uint64 = 0; - int64_t i_int64 = 0; - float i_float = 0; - double i_double = 0; - - long double i_long_double = 0; - long i_long = 0; - unsigned long i_ulong = 0; - long long i_long_long = 0; - unsigned long long i_ulong_long = 0; +TEST_SUITE("pod"); - std::istringstream is(os.str()); - { - IArchive iar(is); - iar(i_bool); - iar(i_char); - iar(i_uchar); - iar(i_uint8); - iar(i_int8); - iar(i_uint16); - iar(i_int16); - iar(i_uint32); - iar(i_int32); - iar(i_uint64); - iar(i_int64); - iar(i_float); - iar(i_double); - iar(i_long_double); - iar(i_long); - iar(i_ulong); - iar(i_long_long); - iar(i_ulong_long); - } - - BOOST_CHECK_EQUAL(i_bool , o_bool); - BOOST_CHECK_EQUAL(i_char , o_char); - BOOST_CHECK_EQUAL(i_uchar , o_uchar); - BOOST_CHECK_EQUAL(i_uint8 , o_uint8); - BOOST_CHECK_EQUAL(i_int8 , o_int8); - BOOST_CHECK_EQUAL(i_uint16 , o_uint16); - BOOST_CHECK_EQUAL(i_int16 , o_int16); - BOOST_CHECK_EQUAL(i_uint32 , o_uint32); - BOOST_CHECK_EQUAL(i_int32 , o_int32); - BOOST_CHECK_EQUAL(i_uint64 , o_uint64); - BOOST_CHECK_EQUAL(i_int64 , o_int64); - BOOST_CHECK_CLOSE(i_float , o_float, (float)1e-5); - BOOST_CHECK_CLOSE(i_double , o_double, 1e-5); - - BOOST_CHECK_CLOSE(i_long_double, o_long_double, 1e-5); - BOOST_CHECK_EQUAL(i_long, o_long); - BOOST_CHECK_EQUAL(i_ulong, o_ulong); - BOOST_CHECK_EQUAL(i_long_long, o_long_long); - BOOST_CHECK_EQUAL(i_ulong_long, o_ulong_long); - } -} - -BOOST_AUTO_TEST_CASE( binary_pod ) +TEST_CASE("binary_pod") { test_pod(); } -BOOST_AUTO_TEST_CASE( portable_binary_pod ) +TEST_CASE("portable_binary_pod") { test_pod(); } -BOOST_AUTO_TEST_CASE( xml_pod ) +TEST_CASE("xml_pod") { test_pod(); } -BOOST_AUTO_TEST_CASE( json_pod ) +TEST_CASE("json_pod") { test_pod(); } + +TEST_SUITE_END(); diff --git a/unittests/pod.hpp b/unittests/pod.hpp new file mode 100644 index 000000000..876d81903 --- /dev/null +++ b/unittests/pod.hpp @@ -0,0 +1,147 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_POD_H_ +#define CEREAL_TEST_POD_H_ +#include "common.hpp" + +template inline +void test_pod() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(size_t i=0; i<100; ++i) + { + bool const o_bool = random_value(gen) % 2 ? true : false; + char const o_char = random_value(gen); + unsigned char const o_uchar = random_value(gen); + uint8_t const o_uint8 = random_value(gen); + int8_t const o_int8 = random_value(gen); + uint16_t const o_uint16 = random_value(gen); + int16_t const o_int16 = random_value(gen); + uint32_t const o_uint32 = random_value(gen); + int32_t const o_int32 = random_value(gen); + uint64_t const o_uint64 = random_value(gen); + int64_t const o_int64 = random_value(gen); + float const o_float = random_value(gen); + double const o_double = random_value(gen); + + long double const o_long_double = random_value(gen); + long const o_long = random_value(gen); + unsigned long const o_ulong = random_value(gen); + long long const o_long_long = random_value(gen); + unsigned long long const o_ulong_long = random_value(gen); + + std::ostringstream os; + { + OArchive oar(os); + oar(o_bool); + oar(o_char); + oar(o_uchar); + oar(o_uint8); + oar(o_int8); + oar(o_uint16); + oar(o_int16); + oar(o_uint32); + oar(o_int32); + oar(o_uint64); + oar(o_int64); + oar(o_float); + oar(o_double); + oar(o_long_double); + oar(o_long); + oar(o_ulong); + oar(o_long_long); + oar(o_ulong_long); + } + + bool i_bool = false; + char i_char = 0; + unsigned char i_uchar = 0; + uint8_t i_uint8 = 0; + int8_t i_int8 = 0; + uint16_t i_uint16 = 0; + int16_t i_int16 = 0; + uint32_t i_uint32 = 0; + int32_t i_int32 = 0; + uint64_t i_uint64 = 0; + int64_t i_int64 = 0; + float i_float = 0; + double i_double = 0; + + long double i_long_double = 0; + long i_long = 0; + unsigned long i_ulong = 0; + long long i_long_long = 0; + unsigned long long i_ulong_long = 0; + + std::istringstream is(os.str()); + { + IArchive iar(is); + iar(i_bool); + iar(i_char); + iar(i_uchar); + iar(i_uint8); + iar(i_int8); + iar(i_uint16); + iar(i_int16); + iar(i_uint32); + iar(i_int32); + iar(i_uint64); + iar(i_int64); + iar(i_float); + iar(i_double); + iar(i_long_double); + iar(i_long); + iar(i_ulong); + iar(i_long_long); + iar(i_ulong_long); + } + + CHECK_EQ(i_bool , o_bool); + CHECK_EQ(i_char , o_char); + CHECK_EQ(i_uchar , o_uchar); + CHECK_EQ(i_uint8 , o_uint8); + CHECK_EQ(i_int8 , o_int8); + CHECK_EQ(i_uint16 , o_uint16); + CHECK_EQ(i_int16 , o_int16); + CHECK_EQ(i_uint32 , o_uint32); + CHECK_EQ(i_int32 , o_int32); + CHECK_EQ(i_uint64 , o_uint64); + CHECK_EQ(i_int64 , o_int64); + CHECK_EQ(i_float , doctest::Approx(o_float).epsilon(1e-5F)); + CHECK_EQ(i_double , doctest::Approx(o_double).epsilon(1e-5)); + + CHECK_EQ(i_long_double, doctest::Approx(o_long_double).epsilon(1e-5L)); + CHECK_EQ(i_long, o_long); + CHECK_EQ(i_ulong, o_ulong); + CHECK_EQ(i_long_long, o_long_long); + CHECK_EQ(i_ulong_long, o_ulong_long); + } +} + +#endif // CEREAL_TEST_POD_H_ diff --git a/unittests/polymorphic.cpp b/unittests/polymorphic.cpp index 15d282a1b..87e6de46f 100644 --- a/unittests/polymorphic.cpp +++ b/unittests/polymorphic.cpp @@ -24,364 +24,51 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "polymorphic.hpp" -#if CEREAL_THREAD_SAFE -#include -static std::mutex boostTestMutex; -#endif - -struct PolyBaseA -{ - virtual void foo() = 0; - virtual ~PolyBaseA() {} -}; - -struct PolyBaseAA : PolyBaseA -{ - PolyBaseAA() {} - PolyBaseAA( long ww ) : w(ww) {} - long w; - - void foo() {} - - template - void serialize( Archive & ar ) - { - ar( w ); - } - - static void doesNothing() - { - cereal::detail::RegisterPolymorphicCaster::bind(); - } - - bool operator==( PolyBaseAA const & other ) const - { - return w == other.w; - } -}; - -struct PolyBaseB : virtual PolyBaseAA -{ - PolyBaseB() {} - PolyBaseB( int xx, long ww ) : PolyBaseAA(ww), x(xx) {} - int x; - - template - void serialize( Archive & ar ) - { - ar( cereal::virtual_base_class( this ) ); - ar( x ); - } - - bool operator==( PolyBaseB const & other ) const - { - return PolyBaseAA::operator==( other ) && - x == other.x; - } -}; - -struct PolyBaseC : virtual PolyBaseAA -{ - PolyBaseC() {} - PolyBaseC( double yy, long ww ) : PolyBaseAA(ww), y(yy) {} - double y; - - template - void serialize( Archive & ar ) - { - ar( cereal::virtual_base_class( this ) ); - ar( y ); - } - - bool operator==( PolyBaseC const & other ) const - { - return PolyBaseAA::operator==( other ) && - std::abs(y - other.y) < 1e-5; - } -}; - -struct PolyDerivedD : PolyBaseB, PolyBaseC -{ - PolyDerivedD() {} - PolyDerivedD( std::string const & zz, double yy, int xx, long ww ) : - PolyBaseAA( ww ), PolyBaseB( xx, ww ), PolyBaseC( yy, ww ), z(zz) {} - std::string z; - - template - void serialize( Archive & ar ) - { - ar( cereal::base_class( this ) ); - ar( cereal::base_class( this ) ); - ar( z ); - } - - bool operator==( PolyDerivedD const & other ) const - { - return PolyBaseB::operator==( other ) && - PolyBaseC::operator==( other ) && - z == other.z; - } -}; +TEST_SUITE("polymorphic"); -CEREAL_REGISTER_TYPE(PolyDerivedD) - -struct PolyBase -{ - PolyBase() {} - PolyBase( int xx, float yy ) : x(xx), y(yy) {} - int x; - float y; - - template - void serialize( Archive & ar ) - { - ar( x, y ); - } - - virtual void foo() = 0; - - bool operator==( PolyBase const & other ) const - { - return x == other.x && std::abs(y - other.y) < 1e-5; - } -}; - -struct PolyDerived : PolyBase -{ - PolyDerived() {} - PolyDerived( int xx, float yy, bool aa, double bb ) : - PolyBase( xx, yy ), a(aa), b(bb) {} - - bool a; - double b; - - template - void serialize( Archive & ar ) - { - ar( cereal::base_class( this ), - a, b ); - } - - bool operator==( PolyDerived const & other ) const - { - return PolyBase::operator==( other ) && a == other.a && std::abs(b - other.b) < 1e-5; - } - - void foo() {} -}; - -CEREAL_REGISTER_TYPE(PolyDerived) - -struct PolyLA : std::enable_shared_from_this -{ - virtual void foo() = 0; -}; - -struct PolyDerivedLA : public PolyLA -{ - PolyDerivedLA( int xx ) : x( xx ) { } - - int x; - std::vector> vec; - - template - void serialize( Archive & ar ) - { - ar( x ); - ar( vec ); - } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - int xx; - ar( xx ); - construct( xx ); - ar( construct->vec ); - } - - void foo() {} - - bool operator==( PolyDerivedLA const & other ) const - { - if( x != other.x ) - return false; - if( vec.size() != other.vec.size() ) - return false; - for( size_t i = 0; i < vec.size(); ++i ) - if( !(*std::dynamic_pointer_cast(vec[i]) == *std::dynamic_pointer_cast(other.vec[i])) ) - return false; - - return true; - } -}; - -CEREAL_REGISTER_TYPE(PolyDerivedLA) -CEREAL_REGISTER_POLYMORPHIC_RELATION(PolyLA, PolyDerivedLA) - -std::ostream& operator<<(std::ostream& os, PolyDerivedLA const & s) -{ - os << "[x: " << s.x << "] "; - for( auto const & v : s.vec ) - os << " child: " << (*std::dynamic_pointer_cast(v)); - return os; -} - -std::ostream& operator<<(std::ostream& os, PolyDerived const & s) -{ - os << "[x: " << s.x << " y: " << s.y << " a: " << s.a << " b: " << s.b << "]"; - return os; -} - -std::ostream& operator<<(std::ostream& os, PolyDerivedD const & s) -{ - os << "[w: " << s.w << " x: " << s.x << " y: " << s.y << " z: " << s.z << "]"; - return os; -} - -template -void test_polymorphic() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rngB = [&](){ return random_value( gen ) % 2 == 0; }; - auto rngI = [&](){ return random_value( gen ); }; - auto rngL = [&](){ return random_value( gen ); }; - auto rngF = [&](){ return random_value( gen ); }; - auto rngD = [&](){ return random_value( gen ); }; - - for(int ii=0; ii<100; ++ii) - { - std::shared_ptr o_shared = std::make_shared( rngI(), rngF(), rngB(), rngD() ); - std::weak_ptr o_weak = o_shared; - std::unique_ptr o_unique( new PolyDerived( rngI(), rngF(), rngB(), rngD() ) ); - - std::shared_ptr o_sharedA = std::make_shared( random_basic_string(gen), - rngD(), rngI(), rngL() ); - - std::weak_ptr o_weakA = o_sharedA; - std::unique_ptr o_uniqueA( new PolyDerivedD( random_basic_string(gen), - rngD(), rngI(), rngL() ) ); - - auto pda = std::make_shared( rngI() ); - pda->vec.emplace_back( std::make_shared( rngI() ) ); - std::shared_ptr o_sharedLA = pda; - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_shared, o_weak, o_unique ); - oar( o_sharedLA ); - - oar( o_sharedA, o_weakA, o_uniqueA ); - } - - decltype(o_shared) i_shared; - decltype(o_weak) i_weak; - decltype(o_unique) i_unique; - - decltype(o_sharedLA) i_sharedLA; - - decltype(o_sharedA) i_sharedA; - decltype(o_weakA) i_weakA; - decltype(o_uniqueA) i_uniqueA; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_shared, i_weak, i_unique ); - iar( i_sharedLA ); - iar( i_sharedA, i_weakA, i_uniqueA ); - } - - auto i_locked = i_weak.lock(); - auto o_locked = o_weak.lock(); - - auto i_sharedLA2 = i_sharedLA->shared_from_this(); - - auto i_lockedA = i_weakA.lock(); - auto o_lockedA = o_weakA.lock(); - - #if CEREAL_THREAD_SAFE - std::lock_guard lock( boostTestMutex ); - #endif - - BOOST_CHECK_EQUAL(i_shared.get(), i_locked.get()); - BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)o_shared.get())); - BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)i_locked.get())); - BOOST_CHECK_EQUAL(*((PolyDerived*)i_locked.get()), *((PolyDerived*)o_locked.get())); - BOOST_CHECK_EQUAL(*((PolyDerived*)i_unique.get()), *((PolyDerived*)o_unique.get())); - - BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA.get()), *((PolyDerivedLA*)o_sharedLA.get())); - BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA2.get()), *((PolyDerivedLA*)o_sharedLA.get())); - - BOOST_CHECK_EQUAL(i_sharedA.get(), i_lockedA.get()); - BOOST_CHECK_EQUAL(*dynamic_cast(i_sharedA.get()), *dynamic_cast(o_sharedA.get())); - BOOST_CHECK_EQUAL(*dynamic_cast(i_sharedA.get()), *dynamic_cast(i_lockedA.get())); - BOOST_CHECK_EQUAL(*dynamic_cast(i_lockedA.get()), *dynamic_cast(o_lockedA.get())); - BOOST_CHECK_EQUAL(*dynamic_cast(i_uniqueA.get()), *dynamic_cast(o_uniqueA.get())); - } -} - -BOOST_AUTO_TEST_CASE( binary_polymorphic ) +TEST_CASE("binary_polymorphic") { test_polymorphic(); } -BOOST_AUTO_TEST_CASE( portable_binary_polymorphic ) +TEST_CASE("portable_binary_polymorphic") { test_polymorphic(); } -BOOST_AUTO_TEST_CASE( xml_polymorphic ) +TEST_CASE("xml_polymorphic") { test_polymorphic(); } -BOOST_AUTO_TEST_CASE( json_polymorphic ) +TEST_CASE("json_polymorphic") { test_polymorphic(); } #if CEREAL_THREAD_SAFE -template -void test_polymorphic_threading() -{ - std::vector> pool; - for( size_t i = 0; i < 100; ++i ) - pool.emplace_back( std::async( std::launch::async, - [](){ test_polymorphic(); return true; } ) ); - - for( auto & future : pool ) - future.wait(); - - for( auto & future : pool ) - BOOST_CHECK( future.get() == true ); -} - -BOOST_AUTO_TEST_CASE( binary_polymorphic_threading ) +TEST_CASE("binary_polymorphic_threading") { test_polymorphic_threading(); } -BOOST_AUTO_TEST_CASE( portable_binary_polymorphic_threading ) +TEST_CASE("portable_binary_polymorphic_threading") { test_polymorphic_threading(); } -BOOST_AUTO_TEST_CASE( xml_polymorphic_threading ) +TEST_CASE("xml_polymorphic_threading") { test_polymorphic_threading(); } -BOOST_AUTO_TEST_CASE( json_polymorphic_threading ) +TEST_CASE("json_polymorphic_threading") { test_polymorphic_threading(); } #endif // CEREAL_THREAD_SAFE + +TEST_SUITE_END(); diff --git a/unittests/polymorphic.hpp b/unittests/polymorphic.hpp new file mode 100644 index 000000000..9309ac4f5 --- /dev/null +++ b/unittests/polymorphic.hpp @@ -0,0 +1,359 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_POLYMORPHIC_H_ +#define CEREAL_TEST_POLYMORPHIC_H_ +#include "common.hpp" + +#if CEREAL_THREAD_SAFE +#include +#endif + +struct PolyBaseA +{ + virtual void foo() = 0; + virtual ~PolyBaseA() {} +}; + +struct PolyBaseAA : PolyBaseA +{ + PolyBaseAA() {} + PolyBaseAA( long ww ) : w(ww) {} + virtual ~PolyBaseAA() {} + long w; + + void foo() {} + + template + void serialize( Archive & ar ) + { + ar( w ); + } + + bool operator==( PolyBaseAA const & other ) const + { + return w == other.w; + } +}; + +CEREAL_REGISTER_POLYMORPHIC_RELATION(PolyBaseA, PolyBaseAA) + +struct PolyBaseB : virtual PolyBaseAA +{ + PolyBaseB() {} + PolyBaseB( int xx, long ww ) : PolyBaseAA(ww), x(xx) {} + virtual ~PolyBaseB() {} + int x; + + template + void serialize( Archive & ar ) + { + ar( cereal::virtual_base_class( this ) ); + ar( x ); + } + + bool operator==( PolyBaseB const & other ) const + { + return PolyBaseAA::operator==( other ) && + x == other.x; + } +}; + +struct PolyBaseC : virtual PolyBaseAA +{ + PolyBaseC() {} + PolyBaseC( double yy, long ww ) : PolyBaseAA(ww), y(yy) {} + virtual ~PolyBaseC() {} + double y; + + template + void serialize( Archive & ar ) + { + ar( cereal::virtual_base_class( this ) ); + ar( y ); + } + + bool operator==( PolyBaseC const & other ) const + { + return PolyBaseAA::operator==( other ) && + std::abs(y - other.y) < 1e-5; + } +}; + +struct PolyDerivedD : PolyBaseB, PolyBaseC +{ + PolyDerivedD() {} + PolyDerivedD( std::string const & zz, double yy, int xx, long ww ) : + PolyBaseAA( ww ), PolyBaseB( xx, ww ), PolyBaseC( yy, ww ), z(zz) {} + virtual ~PolyDerivedD() {} + std::string z; + + template + void serialize( Archive & ar ) + { + ar( cereal::base_class( this ) ); + ar( cereal::base_class( this ) ); + ar( z ); + } + + bool operator==( PolyDerivedD const & other ) const + { + return PolyBaseB::operator==( other ) && + PolyBaseC::operator==( other ) && + z == other.z; + } +}; + +CEREAL_REGISTER_TYPE(PolyDerivedD) + +struct PolyBase +{ + PolyBase() {} + PolyBase( int xx, float yy ) : x(xx), y(yy) {} + virtual ~PolyBase() {} + int x; + float y; + + template + void serialize( Archive & ar ) + { + ar( x, y ); + } + + virtual void foo() = 0; + + bool operator==( PolyBase const & other ) const + { + return x == other.x && std::abs(y - other.y) < 1e-5; + } +}; + +struct PolyDerived : PolyBase +{ + PolyDerived() {} + PolyDerived( int xx, float yy, bool aa, double bb ) : + PolyBase( xx, yy ), a(aa), b(bb) {} + virtual ~PolyDerived() {} + + bool a; + double b; + + template + void serialize( Archive & ar ) + { + ar( cereal::base_class( this ), + a, b ); + } + + bool operator==( PolyDerived const & other ) const + { + return PolyBase::operator==( other ) && a == other.a && std::abs(b - other.b) < 1e-5; + } + + void foo() {} +}; + +CEREAL_REGISTER_TYPE(PolyDerived) + +struct PolyLA : std::enable_shared_from_this +{ + PolyLA() {} + virtual ~PolyLA() {} + virtual void foo() = 0; +}; + +struct PolyDerivedLA : public PolyLA +{ + PolyDerivedLA( int xx ) : x( xx ) { } + virtual ~PolyDerivedLA() {} + + int x; + std::vector> vec; + + template + void serialize( Archive & ar ) + { + ar( x ); + ar( vec ); + } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + int xx; + ar( xx ); + construct( xx ); + ar( construct->vec ); + } + + void foo() {} + + bool operator==( PolyDerivedLA const & other ) const + { + if( x != other.x ) + return false; + if( vec.size() != other.vec.size() ) + return false; + for( size_t i = 0; i < vec.size(); ++i ) + if( !(*std::dynamic_pointer_cast(vec[i]) == *std::dynamic_pointer_cast(other.vec[i])) ) + return false; + + return true; + } +}; + +CEREAL_REGISTER_TYPE(PolyDerivedLA) +CEREAL_REGISTER_POLYMORPHIC_RELATION(PolyLA, PolyDerivedLA) + +std::ostream& operator<<(std::ostream& os, PolyDerivedLA const & s) +{ + os << "[x: " << s.x << "] "; + for( auto const & v : s.vec ) + os << " child: " << (*std::dynamic_pointer_cast(v)); + return os; +} + +std::ostream& operator<<(std::ostream& os, PolyDerived const & s) +{ + os << "[x: " << s.x << " y: " << s.y << " a: " << s.a << " b: " << s.b << "]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, PolyDerivedD const & s) +{ + os << "[w: " << s.w << " x: " << s.x << " y: " << s.y << " z: " << s.z << "]"; + return os; +} + +template inline +void test_polymorphic() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + #if CEREAL_THREAD_SAFE + static std::mutex testMutex; + #endif + + auto rngB = [&](){ return random_value( gen ) % 2 == 0; }; + auto rngI = [&](){ return random_value( gen ); }; + auto rngL = [&](){ return random_value( gen ); }; + auto rngF = [&](){ return random_value( gen ); }; + auto rngD = [&](){ return random_value( gen ); }; + + for(int ii=0; ii<100; ++ii) + { + std::shared_ptr o_shared = std::make_shared( rngI(), rngF(), rngB(), rngD() ); + std::weak_ptr o_weak = o_shared; + std::unique_ptr o_unique( new PolyDerived( rngI(), rngF(), rngB(), rngD() ) ); + + std::shared_ptr o_sharedA = std::make_shared( random_basic_string(gen), + rngD(), rngI(), rngL() ); + + std::weak_ptr o_weakA = o_sharedA; + std::unique_ptr o_uniqueA( new PolyDerivedD( random_basic_string(gen), + rngD(), rngI(), rngL() ) ); + + auto pda = std::make_shared( rngI() ); + pda->vec.emplace_back( std::make_shared( rngI() ) ); + std::shared_ptr o_sharedLA = pda; + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_shared, o_weak, o_unique ); + oar( o_sharedLA ); + + oar( o_sharedA, o_weakA, o_uniqueA ); + } + + decltype(o_shared) i_shared; + decltype(o_weak) i_weak; + decltype(o_unique) i_unique; + + decltype(o_sharedLA) i_sharedLA; + + decltype(o_sharedA) i_sharedA; + decltype(o_weakA) i_weakA; + decltype(o_uniqueA) i_uniqueA; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_shared, i_weak, i_unique ); + iar( i_sharedLA ); + iar( i_sharedA, i_weakA, i_uniqueA ); + } + + auto i_locked = i_weak.lock(); + auto o_locked = o_weak.lock(); + + auto i_sharedLA2 = i_sharedLA->shared_from_this(); + + auto i_lockedA = i_weakA.lock(); + auto o_lockedA = o_weakA.lock(); + + #if CEREAL_THREAD_SAFE + std::lock_guard lock( testMutex ); + #endif + + CHECK_EQ(i_shared.get(), i_locked.get()); + CHECK_EQ(*dynamic_cast(i_shared.get()), *dynamic_cast(o_shared.get())); + CHECK_EQ(*dynamic_cast(i_shared.get()), *dynamic_cast(i_locked.get())); + CHECK_EQ(*dynamic_cast(i_locked.get()), *dynamic_cast(o_locked.get())); + CHECK_EQ(*dynamic_cast(i_unique.get()), *dynamic_cast(o_unique.get())); + + CHECK_EQ(*dynamic_cast(i_sharedLA.get()), *dynamic_cast(o_sharedLA.get())); + CHECK_EQ(*dynamic_cast(i_sharedLA2.get()), *dynamic_cast(o_sharedLA.get())); + + CHECK_EQ(i_sharedA.get(), i_lockedA.get()); + CHECK_EQ(*dynamic_cast(i_sharedA.get()), *dynamic_cast(o_sharedA.get())); + CHECK_EQ(*dynamic_cast(i_sharedA.get()), *dynamic_cast(i_lockedA.get())); + CHECK_EQ(*dynamic_cast(i_lockedA.get()), *dynamic_cast(o_lockedA.get())); + CHECK_EQ(*dynamic_cast(i_uniqueA.get()), *dynamic_cast(o_uniqueA.get())); + } +} + +#if CEREAL_THREAD_SAFE +template inline +void test_polymorphic_threading() +{ + std::vector> pool; + for( size_t i = 0; i < 100; ++i ) + pool.emplace_back( std::async( std::launch::async, + [](){ test_polymorphic(); return true; } ) ); + + for( auto & future : pool ) + future.wait(); + + for( auto & future : pool ) + CHECK_UNARY( future.get() ); +} +#endif // CEREAL_THREAD_SAFE + +#endif // CEREAL_TEST_POLYMORPHIC_H_ diff --git a/unittests/portable_binary_archive.cpp b/unittests/portable_binary_archive.cpp index 479785abd..3b64b0bba 100644 --- a/unittests/portable_binary_archive.cpp +++ b/unittests/portable_binary_archive.cpp @@ -24,146 +24,24 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "portable_binary_archive.hpp" -namespace mynamespace { struct MyCustomClass {}; } +TEST_SUITE("portable_binary_archive"); #ifdef _MSC_VER -BOOST_AUTO_TEST_CASE( util ) +TEST_CASE("util") { - BOOST_CHECK_EQUAL( cereal::util::demangledName(), "struct mynamespace::MyCustomClass" ); + CHECK_EQ( cereal::util::demangledName(), "struct mynamespace::MyCustomClass" ); } #else -BOOST_AUTO_TEST_CASE( util ) +TEST_CASE("util") { - BOOST_CHECK_EQUAL( cereal::util::demangledName(), "mynamespace::MyCustomClass" ); + CHECK_EQ( cereal::util::demangledName(), "mynamespace::MyCustomClass" ); } #endif -template -inline void swapBytes( T & t ) -{ - cereal::portable_binary_detail::swap_bytes( reinterpret_cast(&t) ); -} - -// swaps all output data -#define CEREAL_TEST_SWAP_OUTPUT \ - swapBytes(o_bool); \ - swapBytes(o_uint8); \ - swapBytes(o_int8); \ - swapBytes(o_uint16); \ - swapBytes(o_int16); \ - swapBytes(o_uint32); \ - swapBytes(o_int32); \ - swapBytes(o_uint64); \ - swapBytes(o_int64); \ - swapBytes(o_float); \ - swapBytes(o_double); - -#define CEREAL_TEST_CHECK_EQUAL \ - BOOST_CHECK_EQUAL(i_bool , o_bool); \ - BOOST_CHECK_EQUAL(i_uint8 , o_uint8); \ - BOOST_CHECK_EQUAL(i_int8 , o_int8); \ - BOOST_CHECK_EQUAL(i_uint16 , o_uint16); \ - BOOST_CHECK_EQUAL(i_int16 , o_int16); \ - BOOST_CHECK_EQUAL(i_uint32 , o_uint32); \ - BOOST_CHECK_EQUAL(i_int32 , o_int32); \ - BOOST_CHECK_EQUAL(i_uint64 , o_uint64); \ - BOOST_CHECK_EQUAL(i_int64 , o_int64); \ - if( !std::isnan(i_float) && !std::isnan(o_float) ) BOOST_CHECK_CLOSE(i_float , o_float, (float)1e-5); \ - if( !std::isnan(i_float) && !std::isnan(o_float) ) BOOST_CHECK_CLOSE(i_double , o_double, 1e-5); - -// Last parameter exists to keep everything hidden in options -template -void test_endian_serialization( typename IArchive::Options const & iOptions, typename OArchive::Options const & oOptions, const std::uint8_t inputLittleEndian ) -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(size_t i=0; i<100; ++i) - { - bool o_bool = random_value(gen) % 2 ? true : false; - uint8_t o_uint8 = random_value(gen); - int8_t o_int8 = random_value(gen); - uint16_t o_uint16 = random_value(gen); - int16_t o_int16 = random_value(gen); - uint32_t o_uint32 = random_value(gen); - int32_t o_int32 = random_value(gen); - uint64_t o_uint64 = random_value(gen); - int64_t o_int64 = random_value(gen); - float o_float = random_value(gen); - double o_double = random_value(gen); - - std::vector o_vector(100); - for(auto & elem : o_vector) - elem = random_value(gen); - - std::ostringstream os; - { - OArchive oar(os, oOptions); - oar(o_bool); - oar(o_uint8); - oar(o_int8); - oar(o_uint16); - oar(o_int16); - oar(o_uint32); - oar(o_int32); - oar(o_uint64); - oar(o_int64); - oar(o_float); - oar(o_double); - // We can't test vector directly here since we are artificially interfering with the endianness, - // which can result in the size being incorrect - oar(cereal::binary_data( o_vector.data(), static_cast( o_vector.size() * sizeof(int32_t) ) )); - } - - bool i_bool = false; - uint8_t i_uint8 = 0; - int8_t i_int8 = 0; - uint16_t i_uint16 = 0; - int16_t i_int16 = 0; - uint32_t i_uint32 = 0; - int32_t i_int32 = 0; - uint64_t i_uint64 = 0; - int64_t i_int64 = 0; - float i_float = 0; - double i_double = 0; - std::vector i_vector(100); - - std::istringstream is(os.str()); - { - IArchive iar(is, iOptions); - iar(i_bool); - iar(i_uint8); - iar(i_int8); - iar(i_uint16); - iar(i_int16); - iar(i_uint32); - iar(i_int32); - iar(i_uint64); - iar(i_int64); - iar(i_float); - iar(i_double); - iar(cereal::binary_data( i_vector.data(), static_cast( i_vector.size() * sizeof(int32_t) ) )); - } - - // Convert to big endian if we expect to read big and didn't start big - if( cereal::portable_binary_detail::is_little_endian() ^ inputLittleEndian ) // Convert to little endian if - { - CEREAL_TEST_SWAP_OUTPUT - for( auto & val : o_vector ) - swapBytes(val); - } - - CEREAL_TEST_CHECK_EQUAL - - BOOST_CHECK_EQUAL_COLLECTIONS(i_vector.begin(), i_vector.end(), o_vector.begin(), o_vector.end()); - } -} - -BOOST_AUTO_TEST_CASE( portable_binary_archive_endian_conversions ) +TEST_CASE("portable_binary_archive_endian_conversions") { // (last parameter is whether we load as little endian) test_endian_serialization( @@ -177,7 +55,7 @@ BOOST_AUTO_TEST_CASE( portable_binary_archive_endian_conversions ) } // Tests the default behavior to swap bytes to current machine's endianness -BOOST_AUTO_TEST_CASE( portable_binary_archive_default_behavior ) +TEST_CASE("portable_binary_archive_default_behavior") { std::random_device rd; std::mt19937 gen(rd()); @@ -253,5 +131,4 @@ BOOST_AUTO_TEST_CASE( portable_binary_archive_default_behavior ) } } -#undef CEREAl_TEST_SWAP_DATA -#undef CEREAL_TEST_CHECK_EQUAL +TEST_SUITE_END(); diff --git a/unittests/portable_binary_archive.hpp b/unittests/portable_binary_archive.hpp new file mode 100644 index 000000000..b74c4f96f --- /dev/null +++ b/unittests/portable_binary_archive.hpp @@ -0,0 +1,156 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_PORTABLE_BINARY_ARCHIVE_H_ +#define CEREAL_TEST_PORTABLE_BINARY_ARCHIVE_H_ +#include "common.hpp" + +#include + +namespace mynamespace { struct MyCustomClass {}; } + +template +inline void swapBytes( T & t ) +{ + cereal::portable_binary_detail::swap_bytes( reinterpret_cast(&t) ); +} + +// swaps all output data +#define CEREAL_TEST_SWAP_OUTPUT \ + swapBytes(o_bool); \ + swapBytes(o_uint8); \ + swapBytes(o_int8); \ + swapBytes(o_uint16); \ + swapBytes(o_int16); \ + swapBytes(o_uint32); \ + swapBytes(o_int32); \ + swapBytes(o_uint64); \ + swapBytes(o_int64); \ + swapBytes(o_float); \ + swapBytes(o_double); + +#define CEREAL_TEST_CHECK_EQUAL \ + CHECK_EQ(i_bool , o_bool); \ + CHECK_EQ(i_uint8 , o_uint8); \ + CHECK_EQ(i_int8 , o_int8); \ + CHECK_EQ(i_uint16 , o_uint16); \ + CHECK_EQ(i_int16 , o_int16); \ + CHECK_EQ(i_uint32 , o_uint32); \ + CHECK_EQ(i_int32 , o_int32); \ + CHECK_EQ(i_uint64 , o_uint64); \ + CHECK_EQ(i_int64 , o_int64); \ + if( !std::isnan(i_float) && !std::isnan(o_float) ) CHECK_EQ(i_float , doctest::Approx(o_float).epsilon(1e-5F)); \ + if( !std::isnan(i_float) && !std::isnan(o_float) ) CHECK_EQ(i_double, doctest::Approx(o_double).epsilon(1e-5)); + +// Last parameter exists to keep everything hidden in options +template inline +void test_endian_serialization( typename IArchive::Options const & iOptions, typename OArchive::Options const & oOptions, const std::uint8_t inputLittleEndian ) +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(size_t i=0; i<100; ++i) + { + bool o_bool = random_value(gen) % 2 ? true : false; + uint8_t o_uint8 = random_value(gen); + int8_t o_int8 = random_value(gen); + uint16_t o_uint16 = random_value(gen); + int16_t o_int16 = random_value(gen); + uint32_t o_uint32 = random_value(gen); + int32_t o_int32 = random_value(gen); + uint64_t o_uint64 = random_value(gen); + int64_t o_int64 = random_value(gen); + float o_float = random_value(gen); + double o_double = random_value(gen); + + std::vector o_vector(100); + for(auto & elem : o_vector) + elem = random_value(gen); + + std::ostringstream os; + { + OArchive oar(os, oOptions); + oar(o_bool); + oar(o_uint8); + oar(o_int8); + oar(o_uint16); + oar(o_int16); + oar(o_uint32); + oar(o_int32); + oar(o_uint64); + oar(o_int64); + oar(o_float); + oar(o_double); + // We can't test vector directly here since we are artificially interfering with the endianness, + // which can result in the size being incorrect + oar(cereal::binary_data( o_vector.data(), static_cast( o_vector.size() * sizeof(int32_t) ) )); + } + + bool i_bool = false; + uint8_t i_uint8 = 0; + int8_t i_int8 = 0; + uint16_t i_uint16 = 0; + int16_t i_int16 = 0; + uint32_t i_uint32 = 0; + int32_t i_int32 = 0; + uint64_t i_uint64 = 0; + int64_t i_int64 = 0; + float i_float = 0; + double i_double = 0; + std::vector i_vector(100); + + std::istringstream is(os.str()); + { + IArchive iar(is, iOptions); + iar(i_bool); + iar(i_uint8); + iar(i_int8); + iar(i_uint16); + iar(i_int16); + iar(i_uint32); + iar(i_int32); + iar(i_uint64); + iar(i_int64); + iar(i_float); + iar(i_double); + iar(cereal::binary_data( i_vector.data(), static_cast( i_vector.size() * sizeof(int32_t) ) )); + } + + // Convert to big endian if we expect to read big and didn't start big + if( cereal::portable_binary_detail::is_little_endian() ^ inputLittleEndian ) // Convert to little endian if + { + CEREAL_TEST_SWAP_OUTPUT + for( auto & val : o_vector ) + swapBytes(val); + } + + CEREAL_TEST_CHECK_EQUAL + + check_collection(i_vector, o_vector); + } +} + +#endif // CEREAL_TEST_PORTABLE_BINARY_ARCHIVE_H_ diff --git a/unittests/priority_queue.cpp b/unittests/priority_queue.cpp index 8e0b32fe9..e8b997fc6 100644 --- a/unittests/priority_queue.cpp +++ b/unittests/priority_queue.cpp @@ -24,102 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "priority_queue.hpp" -template -void test_priority_queue() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::priority_queue o_podpriority_queue; - for(int j=0; j<100; ++j) - o_podpriority_queue.push(random_value(gen)); - - std::priority_queue o_iserpriority_queue; - for(int j=0; j<100; ++j) - o_iserpriority_queue.push({ random_value(gen), random_value(gen) }); - - std::priority_queue o_isplpriority_queue; - for(int j=0; j<100; ++j) - o_isplpriority_queue.push({ random_value(gen), random_value(gen) }); - - std::priority_queue o_eserpriority_queue; - for(int j=0; j<100; ++j) - o_eserpriority_queue.push({ random_value(gen), random_value(gen) }); - - std::priority_queue o_esplpriority_queue; - for(int j=0; j<100; ++j) - o_esplpriority_queue.push({ random_value(gen), random_value(gen) }); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podpriority_queue); - oar(o_iserpriority_queue); - oar(o_isplpriority_queue); - oar(o_eserpriority_queue); - oar(o_esplpriority_queue); - } - - std::priority_queue i_podpriority_queue; - std::priority_queue i_iserpriority_queue; - std::priority_queue i_isplpriority_queue; - std::priority_queue i_eserpriority_queue; - std::priority_queue i_esplpriority_queue; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podpriority_queue); - iar(i_iserpriority_queue); - iar(i_isplpriority_queue); - iar(i_eserpriority_queue); - iar(i_esplpriority_queue); - } - - auto & i_podpriority_queue_c = cereal::queue_detail::container(i_podpriority_queue); - auto & i_iserpriority_queue_c = cereal::queue_detail::container(i_iserpriority_queue); - auto & i_isplpriority_queue_c = cereal::queue_detail::container(i_isplpriority_queue); - auto & i_eserpriority_queue_c = cereal::queue_detail::container(i_eserpriority_queue); - auto & i_esplpriority_queue_c = cereal::queue_detail::container(i_esplpriority_queue); - - auto & o_podpriority_queue_c = cereal::queue_detail::container(o_podpriority_queue); - auto & o_iserpriority_queue_c = cereal::queue_detail::container(o_iserpriority_queue); - auto & o_isplpriority_queue_c = cereal::queue_detail::container(o_isplpriority_queue); - auto & o_eserpriority_queue_c = cereal::queue_detail::container(o_eserpriority_queue); - auto & o_esplpriority_queue_c = cereal::queue_detail::container(o_esplpriority_queue); - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podpriority_queue_c.begin(), i_podpriority_queue_c.end(), o_podpriority_queue_c.begin(), o_podpriority_queue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserpriority_queue_c.begin(), i_iserpriority_queue_c.end(), o_iserpriority_queue_c.begin(), o_iserpriority_queue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplpriority_queue_c.begin(), i_isplpriority_queue_c.end(), o_isplpriority_queue_c.begin(), o_isplpriority_queue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserpriority_queue_c.begin(), i_eserpriority_queue_c.end(), o_eserpriority_queue_c.begin(), o_eserpriority_queue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplpriority_queue_c.begin(), i_esplpriority_queue_c.end(), o_esplpriority_queue_c.begin(), o_esplpriority_queue_c.end()); - } -} +TEST_SUITE("priority_queue"); -BOOST_AUTO_TEST_CASE( binary_priority_queue ) +TEST_CASE("binary_priority_queue") { test_priority_queue(); } -BOOST_AUTO_TEST_CASE( portable_binary_priority_queue ) +TEST_CASE("portable_binary_priority_queue") { test_priority_queue(); } -BOOST_AUTO_TEST_CASE( xml_priority_queue ) +TEST_CASE("xml_priority_queue") { test_priority_queue(); } -BOOST_AUTO_TEST_CASE( json_priority_queue ) +TEST_CASE("json_priority_queue") { test_priority_queue(); } +TEST_SUITE_END(); diff --git a/unittests/priority_queue.hpp b/unittests/priority_queue.hpp new file mode 100644 index 000000000..27d31a51d --- /dev/null +++ b/unittests/priority_queue.hpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_PRIORITY_QUEUE_H_ +#define CEREAL_TEST_PRIORITY_QUEUE_H_ +#include "common.hpp" + +template inline +void test_priority_queue() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::priority_queue o_podpriority_queue; + for(int j=0; j<100; ++j) + o_podpriority_queue.push(random_value(gen)); + + std::priority_queue o_iserpriority_queue; + for(int j=0; j<100; ++j) + o_iserpriority_queue.push({ random_value(gen), random_value(gen) }); + + std::priority_queue o_isplpriority_queue; + for(int j=0; j<100; ++j) + o_isplpriority_queue.push({ random_value(gen), random_value(gen) }); + + std::priority_queue o_eserpriority_queue; + for(int j=0; j<100; ++j) + o_eserpriority_queue.push({ random_value(gen), random_value(gen) }); + + std::priority_queue o_esplpriority_queue; + for(int j=0; j<100; ++j) + o_esplpriority_queue.push({ random_value(gen), random_value(gen) }); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podpriority_queue); + oar(o_iserpriority_queue); + oar(o_isplpriority_queue); + oar(o_eserpriority_queue); + oar(o_esplpriority_queue); + } + + std::priority_queue i_podpriority_queue; + std::priority_queue i_iserpriority_queue; + std::priority_queue i_isplpriority_queue; + std::priority_queue i_eserpriority_queue; + std::priority_queue i_esplpriority_queue; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podpriority_queue); + iar(i_iserpriority_queue); + iar(i_isplpriority_queue); + iar(i_eserpriority_queue); + iar(i_esplpriority_queue); + } + + auto & i_podpriority_queue_c = cereal::queue_detail::container(i_podpriority_queue); + auto & i_iserpriority_queue_c = cereal::queue_detail::container(i_iserpriority_queue); + auto & i_isplpriority_queue_c = cereal::queue_detail::container(i_isplpriority_queue); + auto & i_eserpriority_queue_c = cereal::queue_detail::container(i_eserpriority_queue); + auto & i_esplpriority_queue_c = cereal::queue_detail::container(i_esplpriority_queue); + + auto & o_podpriority_queue_c = cereal::queue_detail::container(o_podpriority_queue); + auto & o_iserpriority_queue_c = cereal::queue_detail::container(o_iserpriority_queue); + auto & o_isplpriority_queue_c = cereal::queue_detail::container(o_isplpriority_queue); + auto & o_eserpriority_queue_c = cereal::queue_detail::container(o_eserpriority_queue); + auto & o_esplpriority_queue_c = cereal::queue_detail::container(o_esplpriority_queue); + + check_collection(i_podpriority_queue_c, o_podpriority_queue_c); + check_collection(i_iserpriority_queue_c, o_iserpriority_queue_c); + check_collection(i_isplpriority_queue_c, o_isplpriority_queue_c); + check_collection(i_eserpriority_queue_c, o_eserpriority_queue_c); + check_collection(i_esplpriority_queue_c, o_esplpriority_queue_c); + } +} + +#endif // CEREAL_TEST_PRIORITY_QUEUE_H_ diff --git a/unittests/queue.cpp b/unittests/queue.cpp index 175456e77..5f87705b4 100644 --- a/unittests/queue.cpp +++ b/unittests/queue.cpp @@ -24,102 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "queue.hpp" -template -void test_queue() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::queue o_podqueue; - for(int j=0; j<100; ++j) - o_podqueue.push(random_value(gen)); - - std::queue o_iserqueue; - for(int j=0; j<100; ++j) - o_iserqueue.push({ random_value(gen), random_value(gen) }); - - std::queue o_isplqueue; - for(int j=0; j<100; ++j) - o_isplqueue.push({ random_value(gen), random_value(gen) }); - - std::queue o_eserqueue; - for(int j=0; j<100; ++j) - o_eserqueue.push({ random_value(gen), random_value(gen) }); - - std::queue o_esplqueue; - for(int j=0; j<100; ++j) - o_esplqueue.push({ random_value(gen), random_value(gen) }); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podqueue); - oar(o_iserqueue); - oar(o_isplqueue); - oar(o_eserqueue); - oar(o_esplqueue); - } - - std::queue i_podqueue; - std::queue i_iserqueue; - std::queue i_isplqueue; - std::queue i_eserqueue; - std::queue i_esplqueue; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podqueue); - iar(i_iserqueue); - iar(i_isplqueue); - iar(i_eserqueue); - iar(i_esplqueue); - } - - auto & i_podqueue_c = cereal::queue_detail::container(i_podqueue); - auto & i_iserqueue_c = cereal::queue_detail::container(i_iserqueue); - auto & i_isplqueue_c = cereal::queue_detail::container(i_isplqueue); - auto & i_eserqueue_c = cereal::queue_detail::container(i_eserqueue); - auto & i_esplqueue_c = cereal::queue_detail::container(i_esplqueue); - - auto & o_podqueue_c = cereal::queue_detail::container(o_podqueue); - auto & o_iserqueue_c = cereal::queue_detail::container(o_iserqueue); - auto & o_isplqueue_c = cereal::queue_detail::container(o_isplqueue); - auto & o_eserqueue_c = cereal::queue_detail::container(o_eserqueue); - auto & o_esplqueue_c = cereal::queue_detail::container(o_esplqueue); - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podqueue_c.begin(), i_podqueue_c.end(), o_podqueue_c.begin(), o_podqueue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserqueue_c.begin(), i_iserqueue_c.end(), o_iserqueue_c.begin(), o_iserqueue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplqueue_c.begin(), i_isplqueue_c.end(), o_isplqueue_c.begin(), o_isplqueue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserqueue_c.begin(), i_eserqueue_c.end(), o_eserqueue_c.begin(), o_eserqueue_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplqueue_c.begin(), i_esplqueue_c.end(), o_esplqueue_c.begin(), o_esplqueue_c.end()); - } -} +TEST_SUITE("queue"); -BOOST_AUTO_TEST_CASE( binary_queue ) +TEST_CASE("binary_queue") { test_queue(); } -BOOST_AUTO_TEST_CASE( portable_binary_queue ) +TEST_CASE("portable_binary_queue") { test_queue(); } -BOOST_AUTO_TEST_CASE( xml_queue ) +TEST_CASE("xml_queue") { test_queue(); } -BOOST_AUTO_TEST_CASE( json_queue ) +TEST_CASE("json_queue") { test_queue(); } +TEST_SUITE_END(); diff --git a/unittests/queue.hpp b/unittests/queue.hpp new file mode 100644 index 000000000..3b0484de6 --- /dev/null +++ b/unittests/queue.hpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_QUEUE_H_ +#define CEREAL_TEST_QUEUE_H_ +#include "common.hpp" + +template inline +void test_queue() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::queue o_podqueue; + for(int j=0; j<100; ++j) + o_podqueue.push(random_value(gen)); + + std::queue o_iserqueue; + for(int j=0; j<100; ++j) + o_iserqueue.push({ random_value(gen), random_value(gen) }); + + std::queue o_isplqueue; + for(int j=0; j<100; ++j) + o_isplqueue.push({ random_value(gen), random_value(gen) }); + + std::queue o_eserqueue; + for(int j=0; j<100; ++j) + o_eserqueue.push({ random_value(gen), random_value(gen) }); + + std::queue o_esplqueue; + for(int j=0; j<100; ++j) + o_esplqueue.push({ random_value(gen), random_value(gen) }); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podqueue); + oar(o_iserqueue); + oar(o_isplqueue); + oar(o_eserqueue); + oar(o_esplqueue); + } + + std::queue i_podqueue; + std::queue i_iserqueue; + std::queue i_isplqueue; + std::queue i_eserqueue; + std::queue i_esplqueue; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podqueue); + iar(i_iserqueue); + iar(i_isplqueue); + iar(i_eserqueue); + iar(i_esplqueue); + } + + auto & i_podqueue_c = cereal::queue_detail::container(i_podqueue); + auto & i_iserqueue_c = cereal::queue_detail::container(i_iserqueue); + auto & i_isplqueue_c = cereal::queue_detail::container(i_isplqueue); + auto & i_eserqueue_c = cereal::queue_detail::container(i_eserqueue); + auto & i_esplqueue_c = cereal::queue_detail::container(i_esplqueue); + + auto & o_podqueue_c = cereal::queue_detail::container(o_podqueue); + auto & o_iserqueue_c = cereal::queue_detail::container(o_iserqueue); + auto & o_isplqueue_c = cereal::queue_detail::container(o_isplqueue); + auto & o_eserqueue_c = cereal::queue_detail::container(o_eserqueue); + auto & o_esplqueue_c = cereal::queue_detail::container(o_esplqueue); + + check_collection(i_podqueue_c, o_podqueue_c); + check_collection(i_iserqueue_c, o_iserqueue_c); + check_collection(i_isplqueue_c, o_isplqueue_c); + check_collection(i_eserqueue_c, o_eserqueue_c); + check_collection(i_esplqueue_c, o_esplqueue_c); + } +} + +#endif // CEREAL_TEST_QUEUE_H_ diff --git a/unittests/run_portability_test.cmake b/unittests/run_portability_test.cmake new file mode 100644 index 000000000..2841e6c35 --- /dev/null +++ b/unittests/run_portability_test.cmake @@ -0,0 +1,16 @@ +macro(EXEC_CMD_CHECK) + message("running ${ARGN}") + execute_process(COMMAND ${ARGN} RESULT_VARIABLE CMD_RESULT) + if(CMD_RESULT) + message(FATAL_ERROR "Error running ${ARGN}") + endif() +endmacro() + +set(PORTABILITY_TEST_32 "${PORTABILITY_TEST_DIR}/portability_test32") +set(PORTABILITY_TEST_64 "${PORTABILITY_TEST_DIR}/portability_test64") + +exec_cmd_check(${PORTABILITY_TEST_64} save 64) +exec_cmd_check(${PORTABILITY_TEST_32} load 32) +exec_cmd_check(${PORTABILITY_TEST_32} save 32) +exec_cmd_check(${PORTABILITY_TEST_64} load 64) +exec_cmd_check(${PORTABILITY_TEST_64} remove 64) diff --git a/unittests/run_portability_test.sh b/unittests/run_portability_test.sh deleted file mode 100755 index 718440284..000000000 --- a/unittests/run_portability_test.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e - -./portability_test64 save 64 -./portability_test32 load 32 -./portability_test32 save 32 -./portability_test64 load 64 -./portability_test64 remove 64 diff --git a/unittests/set.cpp b/unittests/set.cpp index e9bb3bb70..cc2e00c0c 100644 --- a/unittests/set.cpp +++ b/unittests/set.cpp @@ -24,90 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "set.hpp" -template -void test_set() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::set o_podset; - for(int j=0; j<100; ++j) - o_podset.insert(random_value(gen)); - - std::set o_iserset; - for(int j=0; j<100; ++j) - o_iserset.insert({ random_value(gen), random_value(gen) }); - - std::set o_isplset; - for(int j=0; j<100; ++j) - o_isplset.insert({ random_value(gen), random_value(gen) }); - - std::set o_eserset; - for(int j=0; j<100; ++j) - o_eserset.insert({ random_value(gen), random_value(gen) }); - - std::set o_esplset; - for(int j=0; j<100; ++j) - o_esplset.insert({ random_value(gen), random_value(gen) }); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podset); - oar(o_iserset); - oar(o_isplset); - oar(o_eserset); - oar(o_esplset); - } - - std::set i_podset; - std::set i_iserset; - std::set i_isplset; - std::set i_eserset; - std::set i_esplset; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podset); - iar(i_iserset); - iar(i_isplset); - iar(i_eserset); - iar(i_esplset); - } - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podset.begin(), i_podset.end(), o_podset.begin(), o_podset.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserset.begin(), i_iserset.end(), o_iserset.begin(), o_iserset.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplset.begin(), i_isplset.end(), o_isplset.begin(), o_isplset.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserset.begin(), i_eserset.end(), o_eserset.begin(), o_eserset.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplset.begin(), i_esplset.end(), o_esplset.begin(), o_esplset.end()); - } -} +TEST_SUITE("set"); -BOOST_AUTO_TEST_CASE( binary_set ) +TEST_CASE("binary_set") { test_set(); } -BOOST_AUTO_TEST_CASE( portable_binary_set ) +TEST_CASE("portable_binary_set") { test_set(); } -BOOST_AUTO_TEST_CASE( xml_set ) +TEST_CASE("xml_set") { test_set(); } -BOOST_AUTO_TEST_CASE( json_set ) +TEST_CASE("json_set") { test_set(); } +TEST_SUITE_END(); diff --git a/unittests/set.hpp b/unittests/set.hpp new file mode 100644 index 000000000..6e3994212 --- /dev/null +++ b/unittests/set.hpp @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_SET_H_ +#define CEREAL_TEST_SET_H_ +#include "common.hpp" + +template inline +void test_set() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::set o_podset; + for(int j=0; j<100; ++j) + o_podset.insert(random_value(gen)); + + std::set o_iserset; + for(int j=0; j<100; ++j) + o_iserset.insert({ random_value(gen), random_value(gen) }); + + std::set o_isplset; + for(int j=0; j<100; ++j) + o_isplset.insert({ random_value(gen), random_value(gen) }); + + std::set o_eserset; + for(int j=0; j<100; ++j) + o_eserset.insert({ random_value(gen), random_value(gen) }); + + std::set o_esplset; + for(int j=0; j<100; ++j) + o_esplset.insert({ random_value(gen), random_value(gen) }); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podset); + oar(o_iserset); + oar(o_isplset); + oar(o_eserset); + oar(o_esplset); + } + + std::set i_podset; + std::set i_iserset; + std::set i_isplset; + std::set i_eserset; + std::set i_esplset; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podset); + iar(i_iserset); + iar(i_isplset); + iar(i_eserset); + iar(i_esplset); + } + + check_collection(i_podset, o_podset); + check_collection(i_iserset, o_iserset); + check_collection(i_isplset, o_isplset); + check_collection(i_eserset, o_eserset); + check_collection(i_esplset, o_esplset); + } +} + +#endif // CEREAL_TEST_SET_H_ diff --git a/unittests/stack.cpp b/unittests/stack.cpp index edc0920d7..3e4212c10 100644 --- a/unittests/stack.cpp +++ b/unittests/stack.cpp @@ -24,102 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "stack.hpp" -template -void test_stack() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::stack o_podstack; - for(int j=0; j<100; ++j) - o_podstack.push(random_value(gen)); - - std::stack o_iserstack; - for(int j=0; j<100; ++j) - o_iserstack.push({ random_value(gen), random_value(gen) }); - - std::stack o_isplstack; - for(int j=0; j<100; ++j) - o_isplstack.push({ random_value(gen), random_value(gen) }); - - std::stack o_eserstack; - for(int j=0; j<100; ++j) - o_eserstack.push({ random_value(gen), random_value(gen) }); - - std::stack o_esplstack; - for(int j=0; j<100; ++j) - o_esplstack.push({ random_value(gen), random_value(gen) }); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podstack); - oar(o_iserstack); - oar(o_isplstack); - oar(o_eserstack); - oar(o_esplstack); - } - - std::stack i_podstack; - std::stack i_iserstack; - std::stack i_isplstack; - std::stack i_eserstack; - std::stack i_esplstack; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podstack); - iar(i_iserstack); - iar(i_isplstack); - iar(i_eserstack); - iar(i_esplstack); - } - - auto & i_podstack_c = cereal::stack_detail::container(i_podstack); - auto & i_iserstack_c = cereal::stack_detail::container(i_iserstack); - auto & i_isplstack_c = cereal::stack_detail::container(i_isplstack); - auto & i_eserstack_c = cereal::stack_detail::container(i_eserstack); - auto & i_esplstack_c = cereal::stack_detail::container(i_esplstack); - - auto & o_podstack_c = cereal::stack_detail::container(o_podstack); - auto & o_iserstack_c = cereal::stack_detail::container(o_iserstack); - auto & o_isplstack_c = cereal::stack_detail::container(o_isplstack); - auto & o_eserstack_c = cereal::stack_detail::container(o_eserstack); - auto & o_esplstack_c = cereal::stack_detail::container(o_esplstack); - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podstack_c.begin(), i_podstack_c.end(), o_podstack_c.begin(), o_podstack_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iserstack_c.begin(), i_iserstack_c.end(), o_iserstack_c.begin(), o_iserstack_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplstack_c.begin(), i_isplstack_c.end(), o_isplstack_c.begin(), o_isplstack_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eserstack_c.begin(), i_eserstack_c.end(), o_eserstack_c.begin(), o_eserstack_c.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplstack_c.begin(), i_esplstack_c.end(), o_esplstack_c.begin(), o_esplstack_c.end()); - } -} +TEST_SUITE("stack"); -BOOST_AUTO_TEST_CASE( binary_stack ) +TEST_CASE("binary_stack") { test_stack(); } -BOOST_AUTO_TEST_CASE( portable_binary_stack ) +TEST_CASE("portable_binary_stack") { test_stack(); } -BOOST_AUTO_TEST_CASE( xml_stack ) +TEST_CASE("xml_stack") { test_stack(); } -BOOST_AUTO_TEST_CASE( json_stack ) +TEST_CASE("json_stack") { test_stack(); } +TEST_SUITE_END(); diff --git a/unittests/stack.hpp b/unittests/stack.hpp new file mode 100644 index 000000000..4ea1ae38b --- /dev/null +++ b/unittests/stack.hpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_STACK_H_ +#define CEREAL_TEST_STACK_H_ +#include "common.hpp" + +template inline +void test_stack() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::stack o_podstack; + for(int j=0; j<100; ++j) + o_podstack.push(random_value(gen)); + + std::stack o_iserstack; + for(int j=0; j<100; ++j) + o_iserstack.push({ random_value(gen), random_value(gen) }); + + std::stack o_isplstack; + for(int j=0; j<100; ++j) + o_isplstack.push({ random_value(gen), random_value(gen) }); + + std::stack o_eserstack; + for(int j=0; j<100; ++j) + o_eserstack.push({ random_value(gen), random_value(gen) }); + + std::stack o_esplstack; + for(int j=0; j<100; ++j) + o_esplstack.push({ random_value(gen), random_value(gen) }); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podstack); + oar(o_iserstack); + oar(o_isplstack); + oar(o_eserstack); + oar(o_esplstack); + } + + std::stack i_podstack; + std::stack i_iserstack; + std::stack i_isplstack; + std::stack i_eserstack; + std::stack i_esplstack; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podstack); + iar(i_iserstack); + iar(i_isplstack); + iar(i_eserstack); + iar(i_esplstack); + } + + auto & i_podstack_c = cereal::stack_detail::container(i_podstack); + auto & i_iserstack_c = cereal::stack_detail::container(i_iserstack); + auto & i_isplstack_c = cereal::stack_detail::container(i_isplstack); + auto & i_eserstack_c = cereal::stack_detail::container(i_eserstack); + auto & i_esplstack_c = cereal::stack_detail::container(i_esplstack); + + auto & o_podstack_c = cereal::stack_detail::container(o_podstack); + auto & o_iserstack_c = cereal::stack_detail::container(o_iserstack); + auto & o_isplstack_c = cereal::stack_detail::container(o_isplstack); + auto & o_eserstack_c = cereal::stack_detail::container(o_eserstack); + auto & o_esplstack_c = cereal::stack_detail::container(o_esplstack); + + check_collection(i_podstack_c, o_podstack_c ); + check_collection(i_iserstack_c, o_iserstack_c); + check_collection(i_isplstack_c, o_isplstack_c); + check_collection(i_eserstack_c, o_eserstack_c); + check_collection(i_esplstack_c, o_esplstack_c); + } +} + +#endif // CEREAL_TEST_STACK_H_ diff --git a/unittests/structs.cpp b/unittests/structs.cpp index 245e15df2..117e7cca5 100644 --- a/unittests/structs.cpp +++ b/unittests/structs.cpp @@ -24,62 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "structs.hpp" -template -void test_structs() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - StructInternalSerialize o_iser = { random_value(gen), random_value(gen) }; - StructInternalSplit o_ispl = { random_value(gen), random_value(gen) }; - StructExternalSerialize o_eser = { random_value(gen), random_value(gen) }; - StructExternalSplit o_espl = { random_value(gen), random_value(gen) }; - - std::ostringstream os; - { - OArchive oar(os); - oar( o_iser, o_ispl, o_eser, o_espl); - } - - StructInternalSerialize i_iser; - StructInternalSplit i_ispl; - StructExternalSerialize i_eser; - StructExternalSplit i_espl; +TEST_SUITE("structs"); - std::istringstream is(os.str()); - { - IArchive iar(is); - iar( i_iser, i_ispl, i_eser, i_espl); - } - - BOOST_CHECK(i_iser == o_iser); - BOOST_CHECK(i_ispl == o_ispl); - BOOST_CHECK(i_eser == o_eser); - BOOST_CHECK(i_espl == o_espl); - } -} - -BOOST_AUTO_TEST_CASE( binary_structs ) +TEST_CASE("binary_structs") { test_structs(); } -BOOST_AUTO_TEST_CASE( portable_binary_structs ) +TEST_CASE("portable_binary_structs") { test_structs(); } -BOOST_AUTO_TEST_CASE( xml_structs ) +TEST_CASE("xml_structs") { test_structs(); } -BOOST_AUTO_TEST_CASE( json_structs ) +TEST_CASE("json_structs") { test_structs(); } + +TEST_SUITE_END(); diff --git a/unittests/structs.hpp b/unittests/structs.hpp new file mode 100644 index 000000000..db7ce1337 --- /dev/null +++ b/unittests/structs.hpp @@ -0,0 +1,68 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_STRUCTS_H_ +#define CEREAL_TEST_STRUCTS_H_ +#include "common.hpp" + +template inline +void test_structs() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + StructInternalSerialize o_iser = { random_value(gen), random_value(gen) }; + StructInternalSplit o_ispl = { random_value(gen), random_value(gen) }; + StructExternalSerialize o_eser = { random_value(gen), random_value(gen) }; + StructExternalSplit o_espl = { random_value(gen), random_value(gen) }; + + std::ostringstream os; + { + OArchive oar(os); + oar( o_iser, o_ispl, o_eser, o_espl); + } + + StructInternalSerialize i_iser; + StructInternalSplit i_ispl; + StructExternalSerialize i_eser; + StructExternalSplit i_espl; + + std::istringstream is(os.str()); + { + IArchive iar(is); + iar( i_iser, i_ispl, i_eser, i_espl); + } + + CHECK_EQ(i_iser, o_iser); + CHECK_EQ(i_ispl, o_ispl); + CHECK_EQ(i_eser, o_eser); + CHECK_EQ(i_espl, o_espl); + } +} + +#endif // CEREAL_TEST_STRUCTS_H_ diff --git a/unittests/structs_minimal.cpp b/unittests/structs_minimal.cpp index 877c65f69..d78f8191e 100644 --- a/unittests/structs_minimal.cpp +++ b/unittests/structs_minimal.cpp @@ -24,248 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "structs_minimal.hpp" -class MemberMinimal -{ - public: - MemberMinimal() = default; - MemberMinimal( std::string const & str ) : x( str ) {} - - protected: - friend class cereal::access; - - template - std::string save_minimal( Archive const & ) const - { - return x; - } - - template - void load_minimal( Archive const &, std::string const & str ) - { - x = str; - } - - public: - std::string x; -}; - -class MemberMinimalVersioned -{ - public: - MemberMinimalVersioned() = default; - MemberMinimalVersioned( double d ) : x( d ) {} - - protected: - friend class cereal::access; - - template - double save_minimal( Archive const &, const std::uint32_t ) const - { - return x; - } - - template - void load_minimal( Archive const &, double const & d, const std::uint32_t ) - { - x = d; - } - - public: - double x; -}; - -struct NonMemberMinimal -{ - NonMemberMinimal() = default; - NonMemberMinimal( std::uint32_t xx ) : x(xx) {} - std::uint32_t x; -}; - -template -std::uint32_t save_minimal( Archive const &, NonMemberMinimal const & nmm ) -{ - return nmm.x; -} - -template -void load_minimal( Archive const &, NonMemberMinimal & nmm, std::uint32_t const & data ) -{ - nmm.x = data; -} - -struct NonMemberMinimalVersioned -{ - NonMemberMinimalVersioned() = default; - NonMemberMinimalVersioned( bool xx ) : x(xx) {} - bool x; -}; - -template -bool save_minimal( Archive const &, NonMemberMinimalVersioned const & nmm, std::uint32_t const ) -{ - return nmm.x; -} - -template -void load_minimal( Archive const &, NonMemberMinimalVersioned & nmm, bool const & data, std::uint32_t const ) -{ - nmm.x = data; -} - -struct TestStruct -{ - TestStruct() = default; - TestStruct( std::string const & s, double d, std::uint32_t u, bool b ) : - mm(s), mmv(d), nmm(u), nmmv(b) {} - - template - void serialize( Archive & ar ) - { - ar( mm, mmv ); - ar( nmm, nmmv ); - } - - MemberMinimal mm; - MemberMinimalVersioned mmv; - NonMemberMinimal nmm; - NonMemberMinimalVersioned nmmv; -}; - -struct Issue79Struct -{ - Issue79Struct() = default; - Issue79Struct( std::int32_t xx ) : x(xx) {} - std::int32_t x; -}; - -template ::value || - std::is_same::value> = cereal::traits::sfinae> -std::string save_minimal( Archive const &, Issue79Struct const & val ) -{ - return std::to_string( val.x ); -} - -template ::value || - std::is_same::value> = cereal::traits::sfinae> -void load_minimal( Archive const &, Issue79Struct & val, std::string const & str ) -{ - val.x = std::stoi( str ); -} - -template ::value || - std::is_same::value> = cereal::traits::sfinae> -std::int32_t save_minimal( Archive const &, Issue79Struct const & val ) -{ - return val.x; -} - -template ::value || - std::is_same::value> = cereal::traits::sfinae> -void load_minimal( Archive const &, Issue79Struct & val, std::int32_t const & xx ) -{ - val.x = xx; -} - -struct Issue79StructInternal -{ - Issue79StructInternal() = default; - Issue79StructInternal( std::int32_t xx ) : x(xx) {} - std::int32_t x; - - template ::value || - std::is_same::value> = cereal::traits::sfinae> - std::string save_minimal( Archive const & ) const - { - return std::to_string( x ); - } +TEST_SUITE("structs_minimal"); - template ::value || - std::is_same::value> = cereal::traits::sfinae> - void load_minimal( Archive const &, std::string const & str ) - { - x = std::stoi( str ); - } - - template ::value || - std::is_same::value> = cereal::traits::sfinae> - std::int32_t save_minimal( Archive const & ) const - { - return x; - } - - template ::value || - std::is_same::value> = cereal::traits::sfinae> - void load_minimal( Archive const &, std::int32_t const & xx ) - { - x = xx; - } -}; - -template -void test_structs_minimal() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - TestStruct o_struct = { random_basic_string(gen), random_value(gen), - random_value(gen), random_value(gen) % 2 ? true : false }; - - Issue79Struct o_struct2 = { random_value(gen) }; - Issue79StructInternal o_struct3 = { random_value(gen) }; - - std::ostringstream os; - { - OArchive oar(os); - oar( o_struct ); - oar( o_struct2 ); - oar( o_struct3 ); - } - - decltype(o_struct) i_struct; - decltype(o_struct2) i_struct2; - decltype(o_struct3) i_struct3; - - std::istringstream is(os.str()); - { - IArchive iar(is); - iar( i_struct ); - iar( i_struct2 ); - iar( i_struct3 ); - } - - BOOST_CHECK(o_struct.mm.x == i_struct.mm.x); - BOOST_CHECK_CLOSE(o_struct.mmv.x, i_struct.mmv.x, 1e-5); - - BOOST_CHECK(o_struct.nmm.x == i_struct.nmm.x); - BOOST_CHECK(o_struct.nmmv.x == i_struct.nmmv.x); - - BOOST_CHECK(o_struct2.x == i_struct2.x); - - BOOST_CHECK(o_struct3.x == i_struct3.x); - } -} - -BOOST_AUTO_TEST_CASE( binary_structs_minimal ) +TEST_CASE("binary_structs_minimal") { test_structs_minimal(); } -BOOST_AUTO_TEST_CASE( portable_binary_structs_minimal ) +TEST_CASE("portable_binary_structs_minimal") { test_structs_minimal(); } -BOOST_AUTO_TEST_CASE( xml_structs_minimal ) +TEST_CASE("xml_structs_minimal") { test_structs_minimal(); } -BOOST_AUTO_TEST_CASE( json_structs_minimal ) +TEST_CASE("json_structs_minimal") { test_structs_minimal(); } + +TEST_SUITE_END(); diff --git a/unittests/structs_minimal.hpp b/unittests/structs_minimal.hpp new file mode 100644 index 000000000..57ccd4999 --- /dev/null +++ b/unittests/structs_minimal.hpp @@ -0,0 +1,254 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_STRUCTS_MINIMAL_H_ +#define CEREAL_TEST_STRUCTS_MINIMAL_H_ +#include "common.hpp" + +class MemberMinimal +{ + public: + MemberMinimal() = default; + MemberMinimal( std::string const & str ) : x( str ) {} + + protected: + friend class cereal::access; + + template + std::string save_minimal( Archive const & ) const + { + return x; + } + + template + void load_minimal( Archive const &, std::string const & str ) + { + x = str; + } + + public: + std::string x; +}; + +class MemberMinimalVersioned +{ + public: + MemberMinimalVersioned() = default; + MemberMinimalVersioned( double d ) : x( d ) {} + + protected: + friend class cereal::access; + + template + double save_minimal( Archive const &, const std::uint32_t ) const + { + return x; + } + + template + void load_minimal( Archive const &, double const & d, const std::uint32_t ) + { + x = d; + } + + public: + double x; +}; + +struct NonMemberMinimal +{ + NonMemberMinimal() = default; + NonMemberMinimal( std::uint32_t xx ) : x(xx) {} + std::uint32_t x; +}; + +template inline +std::uint32_t save_minimal( Archive const &, NonMemberMinimal const & nmm ) +{ + return nmm.x; +} + +template inline +void load_minimal( Archive const &, NonMemberMinimal & nmm, std::uint32_t const & data ) +{ + nmm.x = data; +} + +struct NonMemberMinimalVersioned +{ + NonMemberMinimalVersioned() = default; + NonMemberMinimalVersioned( bool xx ) : x(xx) {} + bool x; +}; + +template inline +bool save_minimal( Archive const &, NonMemberMinimalVersioned const & nmm, std::uint32_t const ) +{ + return nmm.x; +} + +template inline +void load_minimal( Archive const &, NonMemberMinimalVersioned & nmm, bool const & data, std::uint32_t const ) +{ + nmm.x = data; +} + +struct TestStruct +{ + TestStruct() = default; + TestStruct( std::string const & s, double d, std::uint32_t u, bool b ) : + mm(s), mmv(d), nmm(u), nmmv(b) {} + + template + void serialize( Archive & ar ) + { + ar( mm, mmv ); + ar( nmm, nmmv ); + } + + MemberMinimal mm; + MemberMinimalVersioned mmv; + NonMemberMinimal nmm; + NonMemberMinimalVersioned nmmv; +}; + +struct Issue79Struct +{ + Issue79Struct() = default; + Issue79Struct( std::int32_t xx ) : x(xx) {} + std::int32_t x; +}; + +template ::value || + std::is_same::value> = cereal::traits::sfinae> +inline std::string save_minimal( Archive const &, Issue79Struct const & val ) +{ + return std::to_string( val.x ); +} + +template ::value || + std::is_same::value> = cereal::traits::sfinae> +inline void load_minimal( Archive const &, Issue79Struct & val, std::string const & str ) +{ + val.x = std::stoi( str ); +} + +template ::value || + std::is_same::value> = cereal::traits::sfinae> +inline std::int32_t save_minimal( Archive const &, Issue79Struct const & val ) +{ + return val.x; +} + +template ::value || + std::is_same::value> = cereal::traits::sfinae> +inline void load_minimal( Archive const &, Issue79Struct & val, std::int32_t const & xx ) +{ + val.x = xx; +} + +struct Issue79StructInternal +{ + Issue79StructInternal() = default; + Issue79StructInternal( std::int32_t xx ) : x(xx) {} + std::int32_t x; + + template ::value || + std::is_same::value> = cereal::traits::sfinae> + inline std::string save_minimal( Archive const & ) const + { + return std::to_string( x ); + } + + template ::value || + std::is_same::value> = cereal::traits::sfinae> + inline void load_minimal( Archive const &, std::string const & str ) + { + x = std::stoi( str ); + } + + template ::value || + std::is_same::value> = cereal::traits::sfinae> + inline std::int32_t save_minimal( Archive const & ) const + { + return x; + } + + template ::value || + std::is_same::value> = cereal::traits::sfinae> + inline void load_minimal( Archive const &, std::int32_t const & xx ) + { + x = xx; + } +}; + +template inline +void test_structs_minimal() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + TestStruct o_struct = { random_basic_string(gen), random_value(gen), + random_value(gen), random_value(gen) % 2 ? true : false }; + + Issue79Struct o_struct2 = { random_value(gen) }; + Issue79StructInternal o_struct3 = { random_value(gen) }; + + std::ostringstream os; + { + OArchive oar(os); + oar( o_struct ); + oar( o_struct2 ); + oar( o_struct3 ); + } + + decltype(o_struct) i_struct; + decltype(o_struct2) i_struct2; + decltype(o_struct3) i_struct3; + + std::istringstream is(os.str()); + { + IArchive iar(is); + iar( i_struct ); + iar( i_struct2 ); + iar( i_struct3 ); + } + + CHECK_EQ(o_struct.mm.x, i_struct.mm.x); + CHECK_EQ(o_struct.mmv.x, doctest::Approx(i_struct.mmv.x).epsilon(1e-5)); + + CHECK_EQ(o_struct.nmm.x, i_struct.nmm.x); + CHECK_EQ(o_struct.nmmv.x, i_struct.nmmv.x); + + CHECK_EQ(o_struct2.x, i_struct2.x); + + CHECK_EQ(o_struct3.x, i_struct3.x); + } +} + +#endif // CEREAL_TEST_STRUCTS_MINIMAL_H_ diff --git a/unittests/structs_specialized.cpp b/unittests/structs_specialized.cpp index ff92d3d7f..1aa3e672b 100644 --- a/unittests/structs_specialized.cpp +++ b/unittests/structs_specialized.cpp @@ -24,456 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "structs_specialized.hpp" -struct BogusBase -{ - template - void serialize( Archive & ) {} - - template - void save( Archive & ) const {} - - template - void load( Archive & ) {} - - template - int save_minimal( Archive const & ) const { return 0; } - - template - void load_minimal( Archive const &, int const & ) {} -}; - -struct BogusBaseVersioned -{ - template - void serialize( Archive &, const std::uint32_t ) {} - - template - void save( Archive &, const std::uint32_t ) const {} - - template - void load( Archive &, const std::uint32_t ) {} - - template - int save_minimal( Archive const &, const std::uint32_t ) const { return 0; } - - template - void load_minimal( Archive const &, int const &, const std::uint32_t ) {} -}; - -struct BogusBasePolymorphic -{ - template - void serialize( Archive & ) {} - - virtual void doesNothing() {} -}; - -class SpecializedMSerialize : public BogusBase -{ - public: - SpecializedMSerialize() = default; - SpecializedMSerialize( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - void serialize( Archive & ar ) - { - ar( x ); - } -}; - -class SpecializedMSerializeVersioned : public BogusBaseVersioned -{ - public: - SpecializedMSerializeVersioned() = default; - SpecializedMSerializeVersioned( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - void serialize( Archive & ar, const std::uint32_t ) - { - ar( x ); - } -}; - -class SpecializedMSplit : public BogusBase -{ - public: - SpecializedMSplit() = default; - SpecializedMSplit( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - void save( Archive & ar ) const - { - ar( x ); - } - - template - void load( Archive & ar ) - { - ar( x ); - } -}; - -class SpecializedMSplitVersioned : public BogusBaseVersioned -{ - public: - SpecializedMSplitVersioned() = default; - SpecializedMSplitVersioned( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - void save( Archive & ar, const std::uint32_t ) const - { - ar( x ); - } - - template - void load( Archive & ar, const std::uint32_t ) - { - ar( x ); - } -}; - -class SpecializedMSplitPolymorphic : public BogusBasePolymorphic -{ - public: - SpecializedMSplitPolymorphic() = default; - SpecializedMSplitPolymorphic( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - void save( Archive & ar ) const - { - ar( x ); - } - - template - void load( Archive & ar ) - { - ar( x ); - } -}; - -class SpecializedMSplitMinimal : public BogusBase -{ - public: - SpecializedMSplitMinimal() = default; - SpecializedMSplitMinimal( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - int save_minimal( Archive const & ) const - { - return x; - } - - template - void load_minimal( Archive const &, int const & value ) - { - x = value; - } -}; - -class SpecializedMSplitVersionedMinimal : public BogusBaseVersioned -{ - public: - SpecializedMSplitVersionedMinimal() = default; - SpecializedMSplitVersionedMinimal( int xx ) : x(xx) {} - - int x; - - private: - friend class cereal::access; - template - int save_minimal( Archive const &, const std::uint32_t ) const - { - return x; - } - - template - void load_minimal( Archive const &, int const & value, const std::uint32_t ) - { - x = value; - } -}; - -class SpecializedNMSerialize : public BogusBase -{ - public: - SpecializedNMSerialize() = default; - SpecializedNMSerialize( int xx ) : x(xx) {} - - int x; -}; - -template -void serialize( Archive & ar, SpecializedNMSerialize & s ) -{ - ar( s.x ); -} - -class SpecializedNMSerializeVersioned : public BogusBaseVersioned -{ - public: - SpecializedNMSerializeVersioned() = default; - SpecializedNMSerializeVersioned( int xx ) : x(xx) {} - - int x; -}; - -template -void serialize( Archive & ar, SpecializedNMSerializeVersioned & s ) -{ - ar( s.x ); -} - -class SpecializedNMSplit : public BogusBase -{ - public: - SpecializedNMSplit() = default; - SpecializedNMSplit( int xx ) : x(xx) {} - - int x; -}; - -template -void load( Archive & ar, SpecializedNMSplit & s ) -{ - ar( s.x ); -} - -template -void save( Archive & ar, SpecializedNMSplit const & s ) -{ - ar( s.x ); -} - -class SpecializedNMSplitVersioned : public BogusBaseVersioned -{ - public: - SpecializedNMSplitVersioned() = default; - SpecializedNMSplitVersioned( int xx ) : x(xx) {} - - int x; -}; - -template -void load( Archive & ar, SpecializedNMSplitVersioned & s, const std::uint32_t ) -{ - ar( s.x ); -} - -template -void save( Archive & ar, SpecializedNMSplitVersioned const & s, const std::uint32_t ) -{ - ar( s.x ); -} - -class SpecializedNMSplitMinimal : public BogusBase -{ - public: - SpecializedNMSplitMinimal() = default; - SpecializedNMSplitMinimal( int xx ) : x(xx) {} - - int x; -}; - -template -void load_minimal( Archive const &, SpecializedNMSplitMinimal & s, int const & value ) -{ - s.x = value; -} - -template -int save_minimal( Archive const &, SpecializedNMSplitMinimal const & s ) -{ - return s.x; -} - -class SpecializedNMSplitVersionedMinimal : public BogusBaseVersioned -{ - public: - SpecializedNMSplitVersionedMinimal() = default; - SpecializedNMSplitVersionedMinimal( int xx ) : x(xx) {} - - int x; -}; - -template -void load_minimal( Archive const &, SpecializedNMSplitVersionedMinimal & s, int const & value, const std::uint32_t ) -{ - s.x = value; -} - -template -int save_minimal( Archive const &, SpecializedNMSplitVersionedMinimal const & s, const std::uint32_t ) -{ - return s.x; -} - -namespace cereal -{ - template struct specialize {}; - template struct specialize {}; - - template struct specialize {}; - template struct specialize {}; - template struct specialize {}; - - template struct specialize {}; - template struct specialize {}; - - template struct specialize {}; - template struct specialize {}; - - template struct specialize {}; - template struct specialize {}; - - template struct specialize {}; - template struct specialize {}; -} - -CEREAL_REGISTER_TYPE(SpecializedMSplitPolymorphic) -CEREAL_REGISTER_POLYMORPHIC_RELATION(BogusBasePolymorphic, SpecializedMSplitPolymorphic) - -template -void test_structs_specialized() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - SpecializedMSerialize o_iser = { random_value(gen) }; - SpecializedMSerializeVersioned o_iserv = { random_value(gen) }; - - SpecializedMSplit o_ispl = { random_value(gen) }; - SpecializedMSplitVersioned o_isplv = { random_value(gen) }; - - // added re: issue #180 - std::shared_ptr o_shared_ispl = std::make_shared( random_value(gen) ); - - SpecializedMSplitMinimal o_isplm = { random_value(gen) }; - SpecializedMSplitVersionedMinimal o_isplvm = { random_value(gen) }; - - SpecializedNMSerialize o_eser = { random_value(gen) }; - SpecializedNMSerializeVersioned o_eserv = { random_value(gen) }; - - SpecializedNMSplit o_espl = { random_value(gen) }; - SpecializedNMSplitVersioned o_esplv = { random_value(gen) }; - - SpecializedNMSplitMinimal o_esplm = { random_value(gen) }; - SpecializedNMSplitVersionedMinimal o_esplvm = { random_value(gen) }; - - - std::ostringstream os; - { - OArchive oar(os); - - oar( o_iser, o_iserv, - o_ispl, o_isplv, o_shared_ispl, - o_isplm, o_isplvm, - o_eser, o_eserv, - o_espl, o_esplv, - o_esplm, o_esplvm ); - } - - decltype(o_iser) i_iser; - decltype(o_iserv) i_iserv; - - decltype(o_ispl) i_ispl; - decltype(o_isplv) i_isplv; - - decltype(o_shared_ispl) i_shared_ispl; - - decltype(o_isplm) i_isplm; - decltype(o_isplvm) i_isplvm; - - decltype(o_eser) i_eser; - decltype(o_eserv) i_eserv; - - decltype(o_espl) i_espl; - decltype(o_esplv) i_esplv; - - decltype(o_esplm) i_esplm; - decltype(o_esplvm) i_esplvm; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( i_iser, i_iserv, - i_ispl, i_isplv, i_shared_ispl, - i_isplm, i_isplvm, - i_eser, i_eserv, - i_espl, i_esplv, - i_esplm, i_esplvm ); - } - - BOOST_CHECK(i_iser.x == o_iser.x); - BOOST_CHECK(i_iserv.x == o_iserv.x); - - BOOST_CHECK(i_ispl.x == o_ispl.x); - BOOST_CHECK(i_isplv.x == o_isplv.x); - - BOOST_CHECK_EQUAL(((SpecializedMSplitPolymorphic*)i_shared_ispl.get())->x, ((SpecializedMSplitPolymorphic*)o_shared_ispl.get())->x); - - BOOST_CHECK(i_isplm.x == o_isplm.x); - BOOST_CHECK(i_isplvm.x == o_isplvm.x); - - BOOST_CHECK(i_eser.x == o_eser.x); - BOOST_CHECK(i_eserv.x == o_eserv.x); - - BOOST_CHECK(i_espl.x == o_espl.x); - BOOST_CHECK(i_esplv.x == o_esplv.x); - - BOOST_CHECK(i_esplm.x == o_esplm.x); - BOOST_CHECK(i_esplvm.x == o_esplvm.x); - } -} +TEST_SUITE("structs_specialized"); -BOOST_AUTO_TEST_CASE( binary_structs_specialized ) +TEST_CASE("binary_structs_specialized") { test_structs_specialized(); } -BOOST_AUTO_TEST_CASE( portable_binary_structs_specialized ) +TEST_CASE("portable_binary_structs_specialized") { test_structs_specialized(); } -BOOST_AUTO_TEST_CASE( xml_structs_specialized ) +TEST_CASE("xml_structs_specialized") { test_structs_specialized(); } -BOOST_AUTO_TEST_CASE( json_structs_specialized ) +TEST_CASE("json_structs_specialized") { test_structs_specialized(); } +TEST_SUITE_END(); diff --git a/unittests/structs_specialized.hpp b/unittests/structs_specialized.hpp new file mode 100644 index 000000000..8daec99d3 --- /dev/null +++ b/unittests/structs_specialized.hpp @@ -0,0 +1,461 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_STRUCTS_MINIMAL_H_ +#define CEREAL_TEST_STRUCTS_MINIMAL_H_ +#include "common.hpp" + +struct BogusBase +{ + template + void serialize( Archive & ) {} + + template + void save( Archive & ) const {} + + template + void load( Archive & ) {} + + template + int save_minimal( Archive const & ) const { return 0; } + + template + void load_minimal( Archive const &, int const & ) {} +}; + +struct BogusBaseVersioned +{ + template + void serialize( Archive &, const std::uint32_t ) {} + + template + void save( Archive &, const std::uint32_t ) const {} + + template + void load( Archive &, const std::uint32_t ) {} + + template + int save_minimal( Archive const &, const std::uint32_t ) const { return 0; } + + template + void load_minimal( Archive const &, int const &, const std::uint32_t ) {} +}; + +struct BogusBasePolymorphic +{ + template + void serialize( Archive & ) {} + + virtual void doesNothing() {} +}; + +class SpecializedMSerialize : public BogusBase +{ + public: + SpecializedMSerialize() = default; + SpecializedMSerialize( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + void serialize( Archive & ar ) + { + ar( x ); + } +}; + +class SpecializedMSerializeVersioned : public BogusBaseVersioned +{ + public: + SpecializedMSerializeVersioned() = default; + SpecializedMSerializeVersioned( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + void serialize( Archive & ar, const std::uint32_t ) + { + ar( x ); + } +}; + +class SpecializedMSplit : public BogusBase +{ + public: + SpecializedMSplit() = default; + SpecializedMSplit( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + void save( Archive & ar ) const + { + ar( x ); + } + + template + void load( Archive & ar ) + { + ar( x ); + } +}; + +class SpecializedMSplitVersioned : public BogusBaseVersioned +{ + public: + SpecializedMSplitVersioned() = default; + SpecializedMSplitVersioned( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + void save( Archive & ar, const std::uint32_t ) const + { + ar( x ); + } + + template + void load( Archive & ar, const std::uint32_t ) + { + ar( x ); + } +}; + +class SpecializedMSplitPolymorphic : public BogusBasePolymorphic +{ + public: + SpecializedMSplitPolymorphic() = default; + SpecializedMSplitPolymorphic( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + void save( Archive & ar ) const + { + ar( x ); + } + + template + void load( Archive & ar ) + { + ar( x ); + } +}; + +class SpecializedMSplitMinimal : public BogusBase +{ + public: + SpecializedMSplitMinimal() = default; + SpecializedMSplitMinimal( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + int save_minimal( Archive const & ) const + { + return x; + } + + template + void load_minimal( Archive const &, int const & value ) + { + x = value; + } +}; + +class SpecializedMSplitVersionedMinimal : public BogusBaseVersioned +{ + public: + SpecializedMSplitVersionedMinimal() = default; + SpecializedMSplitVersionedMinimal( int xx ) : x(xx) {} + + int x; + + private: + friend class cereal::access; + template + int save_minimal( Archive const &, const std::uint32_t ) const + { + return x; + } + + template + void load_minimal( Archive const &, int const & value, const std::uint32_t ) + { + x = value; + } +}; + +class SpecializedNMSerialize : public BogusBase +{ + public: + SpecializedNMSerialize() = default; + SpecializedNMSerialize( int xx ) : x(xx) {} + + int x; +}; + +template +void serialize( Archive & ar, SpecializedNMSerialize & s ) +{ + ar( s.x ); +} + +class SpecializedNMSerializeVersioned : public BogusBaseVersioned +{ + public: + SpecializedNMSerializeVersioned() = default; + SpecializedNMSerializeVersioned( int xx ) : x(xx) {} + + int x; +}; + +template +void serialize( Archive & ar, SpecializedNMSerializeVersioned & s ) +{ + ar( s.x ); +} + +class SpecializedNMSplit : public BogusBase +{ + public: + SpecializedNMSplit() = default; + SpecializedNMSplit( int xx ) : x(xx) {} + + int x; +}; + +template +void load( Archive & ar, SpecializedNMSplit & s ) +{ + ar( s.x ); +} + +template +void save( Archive & ar, SpecializedNMSplit const & s ) +{ + ar( s.x ); +} + +class SpecializedNMSplitVersioned : public BogusBaseVersioned +{ + public: + SpecializedNMSplitVersioned() = default; + SpecializedNMSplitVersioned( int xx ) : x(xx) {} + + int x; +}; + +template +void load( Archive & ar, SpecializedNMSplitVersioned & s, const std::uint32_t ) +{ + ar( s.x ); +} + +template +void save( Archive & ar, SpecializedNMSplitVersioned const & s, const std::uint32_t ) +{ + ar( s.x ); +} + +class SpecializedNMSplitMinimal : public BogusBase +{ + public: + SpecializedNMSplitMinimal() = default; + SpecializedNMSplitMinimal( int xx ) : x(xx) {} + + int x; +}; + +template +void load_minimal( Archive const &, SpecializedNMSplitMinimal & s, int const & value ) +{ + s.x = value; +} + +template +int save_minimal( Archive const &, SpecializedNMSplitMinimal const & s ) +{ + return s.x; +} + +class SpecializedNMSplitVersionedMinimal : public BogusBaseVersioned +{ + public: + SpecializedNMSplitVersionedMinimal() = default; + SpecializedNMSplitVersionedMinimal( int xx ) : x(xx) {} + + int x; +}; + +template +void load_minimal( Archive const &, SpecializedNMSplitVersionedMinimal & s, int const & value, const std::uint32_t ) +{ + s.x = value; +} + +template +int save_minimal( Archive const &, SpecializedNMSplitVersionedMinimal const & s, const std::uint32_t ) +{ + return s.x; +} + +namespace cereal +{ + template struct specialize {}; + template struct specialize {}; + + template struct specialize {}; + template struct specialize {}; + template struct specialize {}; + + template struct specialize {}; + template struct specialize {}; + + template struct specialize {}; + template struct specialize {}; + + template struct specialize {}; + template struct specialize {}; + + template struct specialize {}; + template struct specialize {}; +} + +CEREAL_REGISTER_TYPE(SpecializedMSplitPolymorphic) +CEREAL_REGISTER_POLYMORPHIC_RELATION(BogusBasePolymorphic, SpecializedMSplitPolymorphic) + +template inline +void test_structs_specialized() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + SpecializedMSerialize o_iser = { random_value(gen) }; + SpecializedMSerializeVersioned o_iserv = { random_value(gen) }; + + SpecializedMSplit o_ispl = { random_value(gen) }; + SpecializedMSplitVersioned o_isplv = { random_value(gen) }; + + // added re: issue #180 + std::shared_ptr o_shared_ispl = std::make_shared( random_value(gen) ); + + SpecializedMSplitMinimal o_isplm = { random_value(gen) }; + SpecializedMSplitVersionedMinimal o_isplvm = { random_value(gen) }; + + SpecializedNMSerialize o_eser = { random_value(gen) }; + SpecializedNMSerializeVersioned o_eserv = { random_value(gen) }; + + SpecializedNMSplit o_espl = { random_value(gen) }; + SpecializedNMSplitVersioned o_esplv = { random_value(gen) }; + + SpecializedNMSplitMinimal o_esplm = { random_value(gen) }; + SpecializedNMSplitVersionedMinimal o_esplvm = { random_value(gen) }; + + + std::ostringstream os; + { + OArchive oar(os); + + oar( o_iser, o_iserv, + o_ispl, o_isplv, o_shared_ispl, + o_isplm, o_isplvm, + o_eser, o_eserv, + o_espl, o_esplv, + o_esplm, o_esplvm ); + } + + decltype(o_iser) i_iser; + decltype(o_iserv) i_iserv; + + decltype(o_ispl) i_ispl; + decltype(o_isplv) i_isplv; + + decltype(o_shared_ispl) i_shared_ispl; + + decltype(o_isplm) i_isplm; + decltype(o_isplvm) i_isplvm; + + decltype(o_eser) i_eser; + decltype(o_eserv) i_eserv; + + decltype(o_espl) i_espl; + decltype(o_esplv) i_esplv; + + decltype(o_esplm) i_esplm; + decltype(o_esplvm) i_esplvm; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( i_iser, i_iserv, + i_ispl, i_isplv, i_shared_ispl, + i_isplm, i_isplvm, + i_eser, i_eserv, + i_espl, i_esplv, + i_esplm, i_esplvm ); + } + + CHECK_EQ(i_iser.x, o_iser.x); + CHECK_EQ(i_iserv.x, o_iserv.x); + + CHECK_EQ(i_ispl.x, o_ispl.x); + CHECK_EQ(i_isplv.x, o_isplv.x); + + CHECK_EQ(dynamic_cast(i_shared_ispl.get())->x, dynamic_cast(o_shared_ispl.get())->x); + + CHECK_EQ(i_isplm.x, o_isplm.x); + CHECK_EQ(i_isplvm.x, o_isplvm.x); + + CHECK_EQ(i_eser.x, o_eser.x); + CHECK_EQ(i_eserv.x, o_eserv.x); + + CHECK_EQ(i_espl.x, o_espl.x); + CHECK_EQ(i_esplv.x, o_esplv.x); + + CHECK_EQ(i_esplm.x, o_esplm.x); + CHECK_EQ(i_esplvm.x, o_esplvm.x); + } +} + +#endif // CEREAL_TEST_STRUCTS_SPECIALIZED_H_ diff --git a/unittests/tuple.cpp b/unittests/tuple.cpp index 973b1a15b..d3ea635da 100644 --- a/unittests/tuple.cpp +++ b/unittests/tuple.cpp @@ -24,96 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "tuple.hpp" -template -void test_tuple() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rng = [&](){ return random_value(gen); }; - - for(int ii=0; ii<100; ++ii) - { - auto o_podtuple = std::make_tuple( rng(), rng(), rng(), rng() ); - auto o_podtuple11 = std::make_tuple( rng(), rng(), rng(), rng(), rng(), rng(), - rng(), rng(), rng(), rng(), rng() ); - auto o_isertuple = std::make_tuple( StructInternalSerialize( rng(), rng() ), - StructInternalSerialize( rng(), rng() ), - StructInternalSerialize( rng(), rng() ), - StructInternalSerialize( rng(), rng() ) ); - auto o_ispltuple = std::make_tuple( StructInternalSplit( rng(), rng() ), - StructInternalSplit( rng(), rng() ), - StructInternalSplit( rng(), rng() ), - StructInternalSplit( rng(), rng() ) ); - auto o_esertuple = std::make_tuple( StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ) ); - auto o_espltuple = std::make_tuple( StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ), - StructExternalSerialize( rng(), rng() ) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podtuple); - oar(o_podtuple11); - oar(o_isertuple); - oar(o_ispltuple); - oar(o_esertuple); - oar(o_espltuple); - } - - decltype( o_podtuple ) i_podtuple; - decltype( o_podtuple11 ) i_podtuple11; - decltype( o_isertuple ) i_isertuple; - decltype( o_ispltuple ) i_ispltuple; - decltype( o_esertuple ) i_esertuple; - decltype( o_espltuple ) i_espltuple; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podtuple); - iar(i_podtuple11); - iar(i_isertuple); - iar(i_ispltuple); - iar(i_esertuple); - iar(i_espltuple); - } - - BOOST_CHECK_EQUAL( i_podtuple == o_podtuple, true ); - BOOST_CHECK_EQUAL( i_podtuple11 == o_podtuple11, true ); - BOOST_CHECK_EQUAL( i_isertuple == o_isertuple, true ); - BOOST_CHECK_EQUAL( i_ispltuple == o_ispltuple, true ); - BOOST_CHECK_EQUAL( i_esertuple == o_esertuple, true ); - BOOST_CHECK_EQUAL( i_espltuple == o_espltuple, true ); - } -} +TEST_SUITE("tuple"); -BOOST_AUTO_TEST_CASE( binary_tuple ) +TEST_CASE("binary_tuple") { test_tuple(); } -BOOST_AUTO_TEST_CASE( portable_binary_tuple ) +TEST_CASE("portable_binary_tuple") { test_tuple(); } -BOOST_AUTO_TEST_CASE( xml_tuple ) +TEST_CASE("xml_tuple") { test_tuple(); } -BOOST_AUTO_TEST_CASE( json_tuple ) +TEST_CASE("json_tuple") { test_tuple(); } +TEST_SUITE_END(); diff --git a/unittests/tuple.hpp b/unittests/tuple.hpp new file mode 100644 index 000000000..edb25b23b --- /dev/null +++ b/unittests/tuple.hpp @@ -0,0 +1,101 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_TUPLE_H_ +#define CEREAL_TEST_TUPLE_H_ +#include "common.hpp" + +template inline +void test_tuple() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rng = [&](){ return random_value(gen); }; + + for(int ii=0; ii<100; ++ii) + { + auto o_podtuple = std::make_tuple( rng(), rng(), rng(), rng() ); + auto o_podtuple11 = std::make_tuple( rng(), rng(), rng(), rng(), rng(), rng(), + rng(), rng(), rng(), rng(), rng() ); + auto o_isertuple = std::make_tuple( StructInternalSerialize( rng(), rng() ), + StructInternalSerialize( rng(), rng() ), + StructInternalSerialize( rng(), rng() ), + StructInternalSerialize( rng(), rng() ) ); + auto o_ispltuple = std::make_tuple( StructInternalSplit( rng(), rng() ), + StructInternalSplit( rng(), rng() ), + StructInternalSplit( rng(), rng() ), + StructInternalSplit( rng(), rng() ) ); + auto o_esertuple = std::make_tuple( StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ) ); + auto o_espltuple = std::make_tuple( StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ), + StructExternalSerialize( rng(), rng() ) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podtuple); + oar(o_podtuple11); + oar(o_isertuple); + oar(o_ispltuple); + oar(o_esertuple); + oar(o_espltuple); + } + + decltype( o_podtuple ) i_podtuple; + decltype( o_podtuple11 ) i_podtuple11; + decltype( o_isertuple ) i_isertuple; + decltype( o_ispltuple ) i_ispltuple; + decltype( o_esertuple ) i_esertuple; + decltype( o_espltuple ) i_espltuple; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podtuple); + iar(i_podtuple11); + iar(i_isertuple); + iar(i_ispltuple); + iar(i_esertuple); + iar(i_espltuple); + } + + CHECK_EQ( i_podtuple, o_podtuple); + CHECK_EQ( i_podtuple11, o_podtuple11); + CHECK_EQ( i_isertuple, o_isertuple); + CHECK_EQ( i_ispltuple, o_ispltuple); + CHECK_EQ( i_esertuple, o_esertuple); + CHECK_EQ( i_espltuple, o_espltuple); + } +} + +#endif // CEREAL_TEST_TUPLE_H_ diff --git a/unittests/unordered_loads.cpp b/unittests/unordered_loads.cpp index 4357b67c3..93772768a 100644 --- a/unittests/unordered_loads.cpp +++ b/unittests/unordered_loads.cpp @@ -24,134 +24,19 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "unordered_loads.hpp" -struct unordered_naming -{ - int x; - int xx; - int y; - int z; - - template - void save( Archive & ar ) const - { - ar( CEREAL_NVP(x), - CEREAL_NVP(z), - CEREAL_NVP(y), - CEREAL_NVP(xx) ); - } - - template - void load( Archive & ar ) - { - ar( x, - CEREAL_NVP(y), - CEREAL_NVP(z), - CEREAL_NVP(xx) ); - } - - bool operator==( unordered_naming const & other ) const - { - return x == other.x && xx == other.xx && y == other.y && z == other.z; - } -}; - -std::ostream& operator<<(std::ostream& os, unordered_naming const & s) -{ - os << "[x: " << s.x << " xx: " << s.xx << " y: " << s.y << " z: " << s.z << "]"; - return os; -} - -template -void test_unordered_loads() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rngB = [&](){ return random_value( gen ) % 2 == 0; }; - auto rngI = [&](){ return random_value( gen ); }; - auto rngF = [&](){ return random_value( gen ); }; - auto rngD = [&](){ return random_value( gen ); }; - auto rngS = [&](){ return random_basic_string( gen ); }; - - for(int ii=0; ii<100; ++ii) - { - auto const name1 = rngS(); - auto const name2 = rngS(); - auto const name3 = rngS(); - auto const name4 = rngS(); - auto const name5 = rngS(); - auto const name6 = rngS(); - auto const name7 = rngS(); - - int o_int1 = rngI(); - double o_double2 = rngD(); - std::vector o_vecbool3 = { rngB(), rngB(), rngB(), rngB(), rngB() }; - int o_int4 = rngI(); - int o_int5 = rngI(); - int o_int6 = rngI(); - std::pair o_un7; - o_un7.first = rngF(); - o_un7.second.x = rngI(); - o_un7.second.xx = rngI(); - o_un7.second.y = rngI(); - o_un7.second.z = rngI(); - - std::ostringstream os; - { - OArchive oar(os); - - oar( cereal::make_nvp( name1, o_int1 ), - cereal::make_nvp( name2, o_double2 ), - cereal::make_nvp( name3, o_vecbool3 ), - cereal::make_nvp( name4, o_int4 ), - cereal::make_nvp( name5, o_int5 ), - cereal::make_nvp( name6, o_int6 ), - cereal::make_nvp( name7, o_un7 ) ); - } - - decltype(o_int1) i_int1; - decltype(o_double2) i_double2; - decltype(o_vecbool3) i_vecbool3; - decltype(o_int4) i_int4; - decltype(o_int5) i_int5; - decltype(o_int6) i_int6; - decltype(o_un7) i_un7; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar( cereal::make_nvp( name7, i_un7 ), - cereal::make_nvp( name2, i_double2 ), - cereal::make_nvp( name4, i_int4 ), - cereal::make_nvp( name3, i_vecbool3 ), - cereal::make_nvp( name1, i_int1 ), - cereal::make_nvp( name5, i_int5 ), - i_int6 ); - } - - BOOST_CHECK_EQUAL(o_int1, i_int1); - BOOST_CHECK_CLOSE(o_double2 , o_double2, 1e-5); - BOOST_CHECK_EQUAL(o_vecbool3.size(), i_vecbool3.size()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_vecbool3.begin(), i_vecbool3.end(), o_vecbool3.begin(), o_vecbool3.end()); - BOOST_CHECK_EQUAL(o_int4, i_int4); - BOOST_CHECK_EQUAL(o_int5, i_int5); - BOOST_CHECK_EQUAL(o_int6, i_int6); - BOOST_CHECK_EQUAL(o_un7.first, i_un7.first); - BOOST_CHECK_EQUAL(o_un7.second, i_un7.second); - } -} +TEST_SUITE("unordered_loads"); -BOOST_AUTO_TEST_CASE( xml_unordered_loads ) +TEST_CASE("xml_unordered_loads") { test_unordered_loads(); } -BOOST_AUTO_TEST_CASE( json_unordered_loads ) +TEST_CASE("json_unordered_loads") { test_unordered_loads(); } +TEST_SUITE_END(); diff --git a/unittests/unordered_loads.hpp b/unittests/unordered_loads.hpp new file mode 100644 index 000000000..278fb651b --- /dev/null +++ b/unittests/unordered_loads.hpp @@ -0,0 +1,149 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_UNORDERED_LOADS_H_ +#define CEREAL_TEST_UNORDERED_LOADS_H_ +#include "common.hpp" + +struct unordered_naming +{ + int x; + int xx; + int y; + int z; + + template + void save( Archive & ar ) const + { + ar( CEREAL_NVP(x), + CEREAL_NVP(z), + CEREAL_NVP(y), + CEREAL_NVP(xx) ); + } + + template + void load( Archive & ar ) + { + ar( x, + CEREAL_NVP(y), + CEREAL_NVP(z), + CEREAL_NVP(xx) ); + } + + bool operator==( unordered_naming const & other ) const + { + return x == other.x && xx == other.xx && y == other.y && z == other.z; + } +}; + +std::ostream& operator<<(std::ostream& os, unordered_naming const & s) +{ + os << "[x: " << s.x << " xx: " << s.xx << " y: " << s.y << " z: " << s.z << "]"; + return os; +} + +template inline +void test_unordered_loads() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rngB = [&](){ return random_value( gen ) % 2 == 0; }; + auto rngI = [&](){ return random_value( gen ); }; + auto rngF = [&](){ return random_value( gen ); }; + auto rngD = [&](){ return random_value( gen ); }; + auto rngS = [&](){ return random_basic_string( gen ); }; + + for(int ii=0; ii<100; ++ii) + { + auto const name1 = rngS(); + auto const name2 = rngS(); + auto const name3 = rngS(); + auto const name4 = rngS(); + auto const name5 = rngS(); + auto const name6 = rngS(); + auto const name7 = rngS(); + + int o_int1 = rngI(); + double o_double2 = rngD(); + std::vector o_vecbool3 = { rngB(), rngB(), rngB(), rngB(), rngB() }; + int o_int4 = rngI(); + int o_int5 = rngI(); + int o_int6 = rngI(); + std::pair o_un7; + o_un7.first = rngF(); + o_un7.second.x = rngI(); + o_un7.second.xx = rngI(); + o_un7.second.y = rngI(); + o_un7.second.z = rngI(); + + std::ostringstream os; + { + OArchive oar(os); + + oar( cereal::make_nvp( name1, o_int1 ), + cereal::make_nvp( name2, o_double2 ), + cereal::make_nvp( name3, o_vecbool3 ), + cereal::make_nvp( name4, o_int4 ), + cereal::make_nvp( name5, o_int5 ), + cereal::make_nvp( name6, o_int6 ), + cereal::make_nvp( name7, o_un7 ) ); + } + + decltype(o_int1) i_int1; + decltype(o_double2) i_double2; + decltype(o_vecbool3) i_vecbool3; + decltype(o_int4) i_int4; + decltype(o_int5) i_int5; + decltype(o_int6) i_int6; + decltype(o_un7) i_un7; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar( cereal::make_nvp( name7, i_un7 ), + cereal::make_nvp( name2, i_double2 ), + cereal::make_nvp( name4, i_int4 ), + cereal::make_nvp( name3, i_vecbool3 ), + cereal::make_nvp( name1, i_int1 ), + cereal::make_nvp( name5, i_int5 ), + i_int6 ); + } + + CHECK_EQ(o_int1, i_int1); + CHECK_EQ(o_double2, doctest::Approx(o_double2).epsilon(1e-5)); + CHECK_EQ(o_vecbool3.size(), i_vecbool3.size()); + check_collection(i_vecbool3, o_vecbool3); + CHECK_EQ(o_int4, i_int4); + CHECK_EQ(o_int5, i_int5); + CHECK_EQ(o_int6, i_int6); + CHECK_EQ(o_un7.first, i_un7.first); + CHECK_EQ(o_un7.second, i_un7.second); + } +} + +#endif // CEREAL_TEST_UNORDERED_LOADS_H_ diff --git a/unittests/unordered_map.cpp b/unittests/unordered_map.cpp index df81833c9..a0c0cbbae 100644 --- a/unittests/unordered_map.cpp +++ b/unittests/unordered_map.cpp @@ -24,119 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "unordered_map.hpp" -template -void test_unordered_map() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::unordered_map o_podunordered_map; - for(int j=0; j<100; ++j) - o_podunordered_map.insert({random_value(gen), random_value(gen)}); - - std::unordered_map o_iserunordered_map; - for(int j=0; j<100; ++j) - o_iserunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::unordered_map o_isplunordered_map; - for(int j=0; j<100; ++j) - o_isplunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::unordered_map o_eserunordered_map; - for(int j=0; j<100; ++j) - o_eserunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::unordered_map o_esplunordered_map; - for(int j=0; j<100; ++j) - o_esplunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podunordered_map); - oar(o_iserunordered_map); - oar(o_isplunordered_map); - oar(o_eserunordered_map); - oar(o_esplunordered_map); - } - - std::unordered_map i_podunordered_map; - std::unordered_map i_iserunordered_map; - std::unordered_map i_isplunordered_map; - std::unordered_map i_eserunordered_map; - std::unordered_map i_esplunordered_map; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podunordered_map); - iar(i_iserunordered_map); - iar(i_isplunordered_map); - iar(i_eserunordered_map); - iar(i_esplunordered_map); - } - - for(auto const & p : i_podunordered_map) - { - auto v = o_podunordered_map.find(p.first); - BOOST_CHECK(v != o_podunordered_map.end()); - BOOST_CHECK_EQUAL(p.second, v->second); - } - - for(auto const & p : i_iserunordered_map) - { - auto v = o_iserunordered_map.find(p.first); - BOOST_CHECK(v != o_iserunordered_map.end()); - BOOST_CHECK_EQUAL(p.second, v->second); - } - - for(auto const & p : i_isplunordered_map) - { - auto v = o_isplunordered_map.find(p.first); - BOOST_CHECK(v != o_isplunordered_map.end()); - BOOST_CHECK_EQUAL(p.second, v->second); - } - - for(auto const & p : i_eserunordered_map) - { - auto v = o_eserunordered_map.find(p.first); - BOOST_CHECK(v != o_eserunordered_map.end()); - BOOST_CHECK_EQUAL(p.second, v->second); - } - - for(auto const & p : i_esplunordered_map) - { - auto v = o_esplunordered_map.find(p.first); - BOOST_CHECK(v != o_esplunordered_map.end()); - BOOST_CHECK_EQUAL(p.second, v->second); - } - } -} +TEST_SUITE("unordered_map"); -BOOST_AUTO_TEST_CASE( binary_unordered_map ) +TEST_CASE("binary_unordered_map") { test_unordered_map(); } -BOOST_AUTO_TEST_CASE( portable_binary_unordered_map ) +TEST_CASE("portable_binary_unordered_map") { test_unordered_map(); } -BOOST_AUTO_TEST_CASE( xml_unordered_map ) +TEST_CASE("xml_unordered_map") { test_unordered_map(); } -BOOST_AUTO_TEST_CASE( json_unordered_map ) +TEST_CASE("json_unordered_map") { test_unordered_map(); } +TEST_SUITE_END(); diff --git a/unittests/unordered_map.hpp b/unittests/unordered_map.hpp new file mode 100644 index 000000000..78961978d --- /dev/null +++ b/unittests/unordered_map.hpp @@ -0,0 +1,124 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_UNORDERED_MAP_H_ +#define CEREAL_TEST_UNORDERED_MAP_H_ +#include "common.hpp" + +template inline +void test_unordered_map() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::unordered_map o_podunordered_map; + for(int j=0; j<100; ++j) + o_podunordered_map.insert({random_value(gen), random_value(gen)}); + + std::unordered_map o_iserunordered_map; + for(int j=0; j<100; ++j) + o_iserunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::unordered_map o_isplunordered_map; + for(int j=0; j<100; ++j) + o_isplunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::unordered_map o_eserunordered_map; + for(int j=0; j<100; ++j) + o_eserunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::unordered_map o_esplunordered_map; + for(int j=0; j<100; ++j) + o_esplunordered_map.insert({random_value(gen), { random_value(gen), random_value(gen) }}); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podunordered_map); + oar(o_iserunordered_map); + oar(o_isplunordered_map); + oar(o_eserunordered_map); + oar(o_esplunordered_map); + } + + std::unordered_map i_podunordered_map; + std::unordered_map i_iserunordered_map; + std::unordered_map i_isplunordered_map; + std::unordered_map i_eserunordered_map; + std::unordered_map i_esplunordered_map; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podunordered_map); + iar(i_iserunordered_map); + iar(i_isplunordered_map); + iar(i_eserunordered_map); + iar(i_esplunordered_map); + } + + for(auto const & p : i_podunordered_map) + { + auto v = o_podunordered_map.find(p.first); + CHECK_NE(v, o_podunordered_map.end()); + CHECK_EQ(p.second, v->second); + } + + for(auto const & p : i_iserunordered_map) + { + auto v = o_iserunordered_map.find(p.first); + CHECK_NE(v, o_iserunordered_map.end()); + CHECK_EQ(p.second, v->second); + } + + for(auto const & p : i_isplunordered_map) + { + auto v = o_isplunordered_map.find(p.first); + CHECK_NE(v, o_isplunordered_map.end()); + CHECK_EQ(p.second, v->second); + } + + for(auto const & p : i_eserunordered_map) + { + auto v = o_eserunordered_map.find(p.first); + CHECK_NE(v, o_eserunordered_map.end()); + CHECK_EQ(p.second, v->second); + } + + for(auto const & p : i_esplunordered_map) + { + auto v = o_esplunordered_map.find(p.first); + CHECK_NE(v, o_esplunordered_map.end()); + CHECK_EQ(p.second, v->second); + } + } +} + +#endif // CEREAL_TEST_UNORDERED_MAP_H_ diff --git a/unittests/unordered_multimap.cpp b/unittests/unordered_multimap.cpp index ad0913d5f..4d9a7c33f 100644 --- a/unittests/unordered_multimap.cpp +++ b/unittests/unordered_multimap.cpp @@ -24,149 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "unordered_multimap.hpp" -template -void test_unordered_multimap() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::unordered_multimap o_podunordered_multimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_podunordered_multimap.insert({key, random_value(gen)}); - o_podunordered_multimap.insert({key, random_value(gen)}); - } - - std::unordered_multimap o_iserunordered_multimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_iserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - o_iserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::unordered_multimap o_isplunordered_multimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_isplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - o_isplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::unordered_multimap o_eserunordered_multimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_eserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - o_eserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::unordered_multimap o_esplunordered_multimap; - for(int j=0; j<100; ++j) - { - auto key = random_value(gen); - o_esplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - o_esplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); - } - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podunordered_multimap); - oar(o_iserunordered_multimap); - oar(o_isplunordered_multimap); - oar(o_eserunordered_multimap); - oar(o_esplunordered_multimap); - } - - std::unordered_multimap i_podunordered_multimap; - std::unordered_multimap i_iserunordered_multimap; - std::unordered_multimap i_isplunordered_multimap; - std::unordered_multimap i_eserunordered_multimap; - std::unordered_multimap i_esplunordered_multimap; - - std::istringstream is(os.str()); - { - IArchive iar(is); +TEST_SUITE("unordered_multimap"); - iar(i_podunordered_multimap); - iar(i_iserunordered_multimap); - iar(i_isplunordered_multimap); - iar(i_eserunordered_multimap); - iar(i_esplunordered_multimap); - } - - BOOST_CHECK_EQUAL(i_podunordered_multimap.size(), o_podunordered_multimap.size()); - BOOST_CHECK_EQUAL(i_iserunordered_multimap.size(), o_iserunordered_multimap.size()); - BOOST_CHECK_EQUAL(i_isplunordered_multimap.size(), o_isplunordered_multimap.size()); - BOOST_CHECK_EQUAL(i_eserunordered_multimap.size(), o_eserunordered_multimap.size()); - BOOST_CHECK_EQUAL(i_esplunordered_multimap.size(), o_esplunordered_multimap.size()); - - for(auto const & p : i_podunordered_multimap) - { - size_t const bucket = o_podunordered_multimap.bucket(p.first); - auto bucket_begin = o_podunordered_multimap.begin(bucket); - auto bucket_end = o_podunordered_multimap.end(bucket); - BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end); - } - - for(auto const & p : i_iserunordered_multimap) - { - size_t const bucket = o_iserunordered_multimap.bucket(p.first); - auto bucket_begin = o_iserunordered_multimap.begin(bucket); - auto bucket_end = o_iserunordered_multimap.end(bucket); - BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end); - } - - for(auto const & p : i_isplunordered_multimap) - { - size_t const bucket = o_isplunordered_multimap.bucket(p.first); - auto bucket_begin = o_isplunordered_multimap.begin(bucket); - auto bucket_end = o_isplunordered_multimap.end(bucket); - BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end); - } - - for(auto const & p : i_eserunordered_multimap) - { - size_t const bucket = o_eserunordered_multimap.bucket(p.first); - auto bucket_begin = o_eserunordered_multimap.begin(bucket); - auto bucket_end = o_eserunordered_multimap.end(bucket); - BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end); - } - - for(auto const & p : i_esplunordered_multimap) - { - size_t const bucket = o_esplunordered_multimap.bucket(p.first); - auto bucket_begin = o_esplunordered_multimap.begin(bucket); - auto bucket_end = o_esplunordered_multimap.end(bucket); - BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end); - } - } -} - -BOOST_AUTO_TEST_CASE( binary_unordered_multimap ) +TEST_CASE("binary_unordered_multimap") { test_unordered_multimap(); } -BOOST_AUTO_TEST_CASE( portable_binary_unordered_multimap ) +TEST_CASE("portable_binary_unordered_multimap") { test_unordered_multimap(); } -BOOST_AUTO_TEST_CASE( xml_unordered_multimap ) +TEST_CASE("xml_unordered_multimap") { test_unordered_multimap(); } -BOOST_AUTO_TEST_CASE( json_unordered_multimap ) +TEST_CASE("json_unordered_multimap") { test_unordered_multimap(); } + +TEST_SUITE_END(); diff --git a/unittests/unordered_multimap.hpp b/unittests/unordered_multimap.hpp new file mode 100644 index 000000000..6f000e6db --- /dev/null +++ b/unittests/unordered_multimap.hpp @@ -0,0 +1,155 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_UNORDERED_MULTIMAP_H_ +#define CEREAL_TEST_UNORDERED_MULTIMAP_H_ +#include "common.hpp" + +template inline +void test_unordered_multimap() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::unordered_multimap o_podunordered_multimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_podunordered_multimap.insert({key, random_value(gen)}); + o_podunordered_multimap.insert({key, random_value(gen)}); + } + + std::unordered_multimap o_iserunordered_multimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_iserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + o_iserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::unordered_multimap o_isplunordered_multimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_isplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + o_isplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::unordered_multimap o_eserunordered_multimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_eserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + o_eserunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::unordered_multimap o_esplunordered_multimap; + for(int j=0; j<100; ++j) + { + auto key = random_value(gen); + o_esplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + o_esplunordered_multimap.insert({key, { random_value(gen), random_value(gen) }}); + } + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podunordered_multimap); + oar(o_iserunordered_multimap); + oar(o_isplunordered_multimap); + oar(o_eserunordered_multimap); + oar(o_esplunordered_multimap); + } + + std::unordered_multimap i_podunordered_multimap; + std::unordered_multimap i_iserunordered_multimap; + std::unordered_multimap i_isplunordered_multimap; + std::unordered_multimap i_eserunordered_multimap; + std::unordered_multimap i_esplunordered_multimap; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podunordered_multimap); + iar(i_iserunordered_multimap); + iar(i_isplunordered_multimap); + iar(i_eserunordered_multimap); + iar(i_esplunordered_multimap); + } + + CHECK_EQ(i_podunordered_multimap.size(), o_podunordered_multimap.size()); + CHECK_EQ(i_iserunordered_multimap.size(), o_iserunordered_multimap.size()); + CHECK_EQ(i_isplunordered_multimap.size(), o_isplunordered_multimap.size()); + CHECK_EQ(i_eserunordered_multimap.size(), o_eserunordered_multimap.size()); + CHECK_EQ(i_esplunordered_multimap.size(), o_esplunordered_multimap.size()); + + for(auto const & p : i_podunordered_multimap) + { + size_t const bucket = o_podunordered_multimap.bucket(p.first); + auto bucket_begin = o_podunordered_multimap.begin(bucket); + auto bucket_end = o_podunordered_multimap.end(bucket); + CHECK_NE(std::find(bucket_begin, bucket_end, p), bucket_end); + } + + for(auto const & p : i_iserunordered_multimap) + { + size_t const bucket = o_iserunordered_multimap.bucket(p.first); + auto bucket_begin = o_iserunordered_multimap.begin(bucket); + auto bucket_end = o_iserunordered_multimap.end(bucket); + CHECK_NE(std::find(bucket_begin, bucket_end, p), bucket_end); + } + + for(auto const & p : i_isplunordered_multimap) + { + size_t const bucket = o_isplunordered_multimap.bucket(p.first); + auto bucket_begin = o_isplunordered_multimap.begin(bucket); + auto bucket_end = o_isplunordered_multimap.end(bucket); + CHECK_NE(std::find(bucket_begin, bucket_end, p), bucket_end); + } + + for(auto const & p : i_eserunordered_multimap) + { + size_t const bucket = o_eserunordered_multimap.bucket(p.first); + auto bucket_begin = o_eserunordered_multimap.begin(bucket); + auto bucket_end = o_eserunordered_multimap.end(bucket); + CHECK_NE(std::find(bucket_begin, bucket_end, p), bucket_end); + } + + for(auto const & p : i_esplunordered_multimap) + { + size_t const bucket = o_esplunordered_multimap.bucket(p.first); + auto bucket_begin = o_esplunordered_multimap.begin(bucket); + auto bucket_end = o_esplunordered_multimap.end(bucket); + CHECK_NE(std::find(bucket_begin, bucket_end, p), bucket_end); + } + } +} + +#endif // CEREAL_TEST_UNORDERED_MULTIMAP_H_ diff --git a/unittests/unordered_multiset.cpp b/unittests/unordered_multiset.cpp index 9e7a56d40..a98ffa17c 100644 --- a/unittests/unordered_multiset.cpp +++ b/unittests/unordered_multiset.cpp @@ -24,129 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "unordered_multiset.hpp" -template -void test_unordered_multiset() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::unordered_multiset o_podunordered_multiset; - for(int j=0; j<100; ++j) - { - int value = random_value(gen); - o_podunordered_multiset.insert(value); - o_podunordered_multiset.insert(value); - } - - std::unordered_multiset> o_iserunordered_multiset; - for(int j=0; j<100; ++j) - { - StructInternalSerialize value = { random_value(gen), random_value(gen) }; - o_iserunordered_multiset.insert(value); - o_iserunordered_multiset.insert(value); - } - - std::unordered_multiset> o_isplunordered_multiset; - for(int j=0; j<100; ++j) - { - StructInternalSplit value = { random_value(gen), random_value(gen) }; - o_isplunordered_multiset.insert(value); - o_isplunordered_multiset.insert(value); - } - - std::unordered_multiset> o_eserunordered_multiset; - for(int j=0; j<100; ++j) - { - StructExternalSerialize value = { random_value(gen), random_value(gen) }; - o_eserunordered_multiset.insert(value); - o_eserunordered_multiset.insert(value); - } - - std::unordered_multiset> o_esplunordered_multiset; - for(int j=0; j<100; ++j) - { - StructExternalSplit value = { random_value(gen), random_value(gen) }; - o_esplunordered_multiset.insert(value); - o_esplunordered_multiset.insert(value); - } - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podunordered_multiset); - oar(o_iserunordered_multiset); - oar(o_isplunordered_multiset); - oar(o_eserunordered_multiset); - oar(o_esplunordered_multiset); - } - - std::unordered_multiset i_podunordered_multiset; - std::unordered_multiset> i_iserunordered_multiset; - std::unordered_multiset> i_isplunordered_multiset; - std::unordered_multiset> i_eserunordered_multiset; - std::unordered_multiset> i_esplunordered_multiset; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podunordered_multiset); - iar(i_iserunordered_multiset); - iar(i_isplunordered_multiset); - iar(i_eserunordered_multiset); - iar(i_esplunordered_multiset); - } - - for(auto const & p : i_podunordered_multiset) - { - BOOST_CHECK_EQUAL(o_podunordered_multiset.count(p), i_podunordered_multiset.count(p)); - } - - for(auto const & p : i_iserunordered_multiset) - { - BOOST_CHECK_EQUAL(o_iserunordered_multiset.count(p), i_iserunordered_multiset.count(p)); - } - - for(auto const & p : i_isplunordered_multiset) - { - BOOST_CHECK_EQUAL(o_isplunordered_multiset.count(p), i_isplunordered_multiset.count(p)); - } - - for(auto const & p : i_eserunordered_multiset) - { - BOOST_CHECK_EQUAL(o_eserunordered_multiset.count(p), i_eserunordered_multiset.count(p)); - } - - for(auto const & p : i_esplunordered_multiset) - { - BOOST_CHECK_EQUAL(o_esplunordered_multiset.count(p), i_esplunordered_multiset.count(p)); - } - } -} +TEST_SUITE("unordered_multiset"); -BOOST_AUTO_TEST_CASE( binary_unordered_multiset ) +TEST_CASE("binary_unordered_multiset") { test_unordered_multiset(); } -BOOST_AUTO_TEST_CASE( portable_binary_unordered_multiset ) +TEST_CASE("portable_binary_unordered_multiset") { test_unordered_multiset(); } -BOOST_AUTO_TEST_CASE( xml_unordered_multiset ) +TEST_CASE("xml_unordered_multiset") { test_unordered_multiset(); } -BOOST_AUTO_TEST_CASE( json_unordered_multiset ) +TEST_CASE("json_unordered_multiset") { test_unordered_multiset(); } +TEST_SUITE_END(); diff --git a/unittests/unordered_multiset.hpp b/unittests/unordered_multiset.hpp new file mode 100644 index 000000000..ae9d07236 --- /dev/null +++ b/unittests/unordered_multiset.hpp @@ -0,0 +1,134 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_UNORDERED_MULTISET_H_ +#define CEREAL_TEST_UNORDERED_MULTISET_H_ +#include "common.hpp" + +template inline +void test_unordered_multiset() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::unordered_multiset o_podunordered_multiset; + for(int j=0; j<100; ++j) + { + int value = random_value(gen); + o_podunordered_multiset.insert(value); + o_podunordered_multiset.insert(value); + } + + std::unordered_multiset> o_iserunordered_multiset; + for(int j=0; j<100; ++j) + { + StructInternalSerialize value = { random_value(gen), random_value(gen) }; + o_iserunordered_multiset.insert(value); + o_iserunordered_multiset.insert(value); + } + + std::unordered_multiset> o_isplunordered_multiset; + for(int j=0; j<100; ++j) + { + StructInternalSplit value = { random_value(gen), random_value(gen) }; + o_isplunordered_multiset.insert(value); + o_isplunordered_multiset.insert(value); + } + + std::unordered_multiset> o_eserunordered_multiset; + for(int j=0; j<100; ++j) + { + StructExternalSerialize value = { random_value(gen), random_value(gen) }; + o_eserunordered_multiset.insert(value); + o_eserunordered_multiset.insert(value); + } + + std::unordered_multiset> o_esplunordered_multiset; + for(int j=0; j<100; ++j) + { + StructExternalSplit value = { random_value(gen), random_value(gen) }; + o_esplunordered_multiset.insert(value); + o_esplunordered_multiset.insert(value); + } + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podunordered_multiset); + oar(o_iserunordered_multiset); + oar(o_isplunordered_multiset); + oar(o_eserunordered_multiset); + oar(o_esplunordered_multiset); + } + + std::unordered_multiset i_podunordered_multiset; + std::unordered_multiset> i_iserunordered_multiset; + std::unordered_multiset> i_isplunordered_multiset; + std::unordered_multiset> i_eserunordered_multiset; + std::unordered_multiset> i_esplunordered_multiset; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podunordered_multiset); + iar(i_iserunordered_multiset); + iar(i_isplunordered_multiset); + iar(i_eserunordered_multiset); + iar(i_esplunordered_multiset); + } + + for(auto const & p : i_podunordered_multiset) + { + CHECK_EQ(o_podunordered_multiset.count(p), i_podunordered_multiset.count(p)); + } + + for(auto const & p : i_iserunordered_multiset) + { + CHECK_EQ(o_iserunordered_multiset.count(p), i_iserunordered_multiset.count(p)); + } + + for(auto const & p : i_isplunordered_multiset) + { + CHECK_EQ(o_isplunordered_multiset.count(p), i_isplunordered_multiset.count(p)); + } + + for(auto const & p : i_eserunordered_multiset) + { + CHECK_EQ(o_eserunordered_multiset.count(p), i_eserunordered_multiset.count(p)); + } + + for(auto const & p : i_esplunordered_multiset) + { + CHECK_EQ(o_esplunordered_multiset.count(p), i_esplunordered_multiset.count(p)); + } + } +} + +#endif // CEREAL_TEST_UNORDERED_MULTISET_H_ diff --git a/unittests/unordered_set.cpp b/unittests/unordered_set.cpp index a4b16b971..0c8be1436 100644 --- a/unittests/unordered_set.cpp +++ b/unittests/unordered_set.cpp @@ -24,110 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "unordered_set.hpp" -template -void test_unordered_set() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::unordered_set o_podunordered_set; - for(int j=0; j<100; ++j) - o_podunordered_set.insert(random_value(gen)); - - std::unordered_set> o_iserunordered_set; - for(int j=0; j<100; ++j) - o_iserunordered_set.insert({ random_value(gen), random_value(gen) }); - - std::unordered_set> o_isplunordered_set; - for(int j=0; j<100; ++j) - o_isplunordered_set.insert({ random_value(gen), random_value(gen) }); - - std::unordered_set> o_eserunordered_set; - for(int j=0; j<100; ++j) - o_eserunordered_set.insert({ random_value(gen), random_value(gen) }); - - std::unordered_set> o_esplunordered_set; - for(int j=0; j<100; ++j) - o_esplunordered_set.insert({ random_value(gen), random_value(gen) }); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podunordered_set); - oar(o_iserunordered_set); - oar(o_isplunordered_set); - oar(o_eserunordered_set); - oar(o_esplunordered_set); - } - - std::unordered_set i_podunordered_set; - std::unordered_set> i_iserunordered_set; - std::unordered_set> i_isplunordered_set; - std::unordered_set> i_eserunordered_set; - std::unordered_set> i_esplunordered_set; +TEST_SUITE("unordered_set"); - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podunordered_set); - iar(i_iserunordered_set); - iar(i_isplunordered_set); - iar(i_eserunordered_set); - iar(i_esplunordered_set); - } - - for(auto const & p : i_podunordered_set) - { - BOOST_CHECK_EQUAL(o_podunordered_set.count(p), 1lu); - } - - for(auto const & p : i_iserunordered_set) - { - BOOST_CHECK_EQUAL(o_iserunordered_set.count(p), 1lu); - } - - for(auto const & p : i_isplunordered_set) - { - BOOST_CHECK_EQUAL(o_isplunordered_set.count(p), 1lu); - } - - for(auto const & p : i_eserunordered_set) - { - BOOST_CHECK_EQUAL(o_eserunordered_set.count(p), 1lu); - } - - for(auto const & p : i_esplunordered_set) - { - BOOST_CHECK_EQUAL(o_esplunordered_set.count(p), 1lu); - } - } -} - -BOOST_AUTO_TEST_CASE( binary_unordered_set ) +TEST_CASE("binary_unordered_set") { test_unordered_set(); } -BOOST_AUTO_TEST_CASE( portable_binary_unordered_set ) +TEST_CASE("portable_binary_unordered_set") { test_unordered_set(); } -BOOST_AUTO_TEST_CASE( xml_unordered_set ) +TEST_CASE("xml_unordered_set") { test_unordered_set(); } -BOOST_AUTO_TEST_CASE( json_unordered_set ) +TEST_CASE("json_unordered_set") { test_unordered_set(); } - +TEST_SUITE_END(); diff --git a/unittests/unordered_set.hpp b/unittests/unordered_set.hpp new file mode 100644 index 000000000..334731363 --- /dev/null +++ b/unittests/unordered_set.hpp @@ -0,0 +1,114 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_UNORDERED_SET_H_ +#define CEREAL_TEST_UNORDERED_SET_H_ +#include "common.hpp" + +template inline +void test_unordered_set() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::unordered_set o_podunordered_set; + for(int j=0; j<100; ++j) + o_podunordered_set.insert(random_value(gen)); + + std::unordered_set> o_iserunordered_set; + for(int j=0; j<100; ++j) + o_iserunordered_set.insert({ random_value(gen), random_value(gen) }); + + std::unordered_set> o_isplunordered_set; + for(int j=0; j<100; ++j) + o_isplunordered_set.insert({ random_value(gen), random_value(gen) }); + + std::unordered_set> o_eserunordered_set; + for(int j=0; j<100; ++j) + o_eserunordered_set.insert({ random_value(gen), random_value(gen) }); + + std::unordered_set> o_esplunordered_set; + for(int j=0; j<100; ++j) + o_esplunordered_set.insert({ random_value(gen), random_value(gen) }); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podunordered_set); + oar(o_iserunordered_set); + oar(o_isplunordered_set); + oar(o_eserunordered_set); + oar(o_esplunordered_set); + } + + std::unordered_set i_podunordered_set; + std::unordered_set> i_iserunordered_set; + std::unordered_set> i_isplunordered_set; + std::unordered_set> i_eserunordered_set; + std::unordered_set> i_esplunordered_set; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podunordered_set); + iar(i_iserunordered_set); + iar(i_isplunordered_set); + iar(i_eserunordered_set); + iar(i_esplunordered_set); + } + + for(auto const & p : i_podunordered_set) + { + CHECK_EQ(o_podunordered_set.count(p), 1lu); + } + + for(auto const & p : i_iserunordered_set) + { + CHECK_EQ(o_iserunordered_set.count(p), 1lu); + } + + for(auto const & p : i_isplunordered_set) + { + CHECK_EQ(o_isplunordered_set.count(p), 1lu); + } + + for(auto const & p : i_eserunordered_set) + { + CHECK_EQ(o_eserunordered_set.count(p), 1lu); + } + + for(auto const & p : i_esplunordered_set) + { + CHECK_EQ(o_esplunordered_set.count(p), 1lu); + } + } +} + +#endif // CEREAL_TEST_UNORDERED_SET_H_ diff --git a/unittests/user_data_adapters.cpp b/unittests/user_data_adapters.cpp index 429d60500..9a8884806 100644 --- a/unittests/user_data_adapters.cpp +++ b/unittests/user_data_adapters.cpp @@ -24,114 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#define CEREAL_FUTURE_EXPERIMENTAL -#include -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "user_data_adapters.hpp" -struct SomeStruct {}; +TEST_SUITE("user_data_adapters"); -struct UserData -{ - UserData( SomeStruct * pp, SomeStruct & r ) : - p(pp), ref(r) {} - - SomeStruct * p; - std::reference_wrapper ref; -}; - -struct UserStruct -{ - UserStruct( std::int32_t i, - SomeStruct * pointer, - SomeStruct & reference ) : - i32( i ), - p( pointer ), - ref( reference ) - { } - - UserStruct & operator=( UserStruct const & ) = delete; - - std::int32_t i32; - SomeStruct const * p; - SomeStruct & ref; - - template - void serialize( Archive & ar ) - { - ar( i32 ); - } - - template - static void load_and_construct( Archive & ar, cereal::construct & construct ) - { - std::int32_t ii; - ar( ii ); - auto & data = cereal::get_user_data( ar ); - construct( ii, data.p, data.ref.get() ); - } -}; - -template -void test_user_data_adapters() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - auto rng = [&](){ return random_value(gen); }; - - for(int ii=0; ii<100; ++ii) - { - SomeStruct ss; - std::unique_ptr o_ptr( new UserStruct( rng(), &ss, ss ) ); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_ptr); - } - - decltype( o_ptr ) i_ptr; - - std::istringstream is(os.str()); - { - UserData ud(&ss, ss); - cereal::UserDataAdapter iar(ud, is); - - iar(i_ptr); - } - - BOOST_CHECK_EQUAL( i_ptr->p == o_ptr->p, true ); - BOOST_CHECK_EQUAL( std::addressof(i_ptr->ref) == std::addressof(o_ptr->ref), true ); - BOOST_CHECK_EQUAL( i_ptr->i32, o_ptr->i32 ); - - std::istringstream bad_is(os.str()); - { - IArchive iar(bad_is); - - BOOST_CHECK_THROW( iar(i_ptr), ::cereal::Exception ); - } - } -} - -BOOST_AUTO_TEST_CASE( binary_user_data_adapters ) +TEST_CASE("binary_user_data_adapters") { test_user_data_adapters(); } -BOOST_AUTO_TEST_CASE( portable_binary_user_data_adapters ) +TEST_CASE("portable_binary_user_data_adapters") { test_user_data_adapters(); } -BOOST_AUTO_TEST_CASE( xml_user_data_adapters ) +TEST_CASE("xml_user_data_adapters") { test_user_data_adapters(); } -BOOST_AUTO_TEST_CASE( json_user_data_adapters ) +TEST_CASE("json_user_data_adapters") { test_user_data_adapters(); } +TEST_SUITE_END(); diff --git a/unittests/user_data_adapters.hpp b/unittests/user_data_adapters.hpp new file mode 100644 index 000000000..23a2510c0 --- /dev/null +++ b/unittests/user_data_adapters.hpp @@ -0,0 +1,120 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_USER_DATA_ADAPTERS_H_ +#define CEREAL_TEST_USER_DATA_ADAPTERS_H_ + +#include "common.hpp" +#define CEREAL_FUTURE_EXPERIMENTAL +#include + +struct SomeStruct {}; + +struct UserData +{ + UserData( SomeStruct * pp, SomeStruct & r ) : + p(pp), ref(r) {} + + SomeStruct * p; + std::reference_wrapper ref; +}; + +struct UserStruct +{ + UserStruct( std::int32_t i, + SomeStruct * pointer, + SomeStruct & reference ) : + i32( i ), + p( pointer ), + ref( reference ) + { } + + UserStruct & operator=( UserStruct const & ) = delete; + + std::int32_t i32; + SomeStruct const * p; + SomeStruct & ref; + + template + void serialize( Archive & ar ) + { + ar( i32 ); + } + + template + static void load_and_construct( Archive & ar, cereal::construct & construct ) + { + std::int32_t ii; + ar( ii ); + auto & data = cereal::get_user_data( ar ); + construct( ii, data.p, data.ref.get() ); + } +}; + +template inline +void test_user_data_adapters() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + auto rng = [&](){ return random_value(gen); }; + + for(int ii=0; ii<100; ++ii) + { + SomeStruct ss; + std::unique_ptr o_ptr( new UserStruct( rng(), &ss, ss ) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_ptr); + } + + decltype( o_ptr ) i_ptr; + + std::istringstream is(os.str()); + { + UserData ud(&ss, ss); + cereal::UserDataAdapter iar(ud, is); + + iar(i_ptr); + } + + CHECK_EQ( i_ptr->p, o_ptr->p ); + CHECK_EQ( std::addressof(i_ptr->ref), std::addressof(o_ptr->ref) ); + CHECK_EQ( i_ptr->i32, o_ptr->i32 ); + + std::istringstream bad_is(os.str()); + { + IArchive iar(bad_is); + + CHECK_THROWS_AS( iar(i_ptr), ::cereal::Exception ); + } + } +} + +#endif // CEREAL_TEST_USER_DATA_ADAPTERS_H_ diff --git a/unittests/valarray.cpp b/unittests/valarray.cpp index 7a1fbd1f5..4866c0297 100644 --- a/unittests/valarray.cpp +++ b/unittests/valarray.cpp @@ -24,96 +24,29 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "valarray.hpp" -#include "common.hpp" -#include +TEST_SUITE("valarray"); -template -void test_valarray() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for (int ii = 0; ii<100; ++ii) - { - std::valarray o_podvalarray(100); - for (auto & elem : o_podvalarray) - elem = random_value(gen); - - std::valarray o_iservalarray(100); - for (auto & elem : o_iservalarray) - elem = StructInternalSerialize(random_value(gen), random_value(gen)); - - std::valarray o_isplvalarray(100); - for (auto & elem : o_isplvalarray) - elem = StructInternalSplit(random_value(gen), random_value(gen)); - - std::valarray o_eservalarray(100); - for (auto & elem : o_eservalarray) - elem = StructExternalSerialize(random_value(gen), random_value(gen)); - - std::valarray o_esplvalarray(100); - for (auto & elem : o_esplvalarray) - elem = StructExternalSplit(random_value(gen), random_value(gen)); - - std::ostringstream os; - { - OArchive oar(os); - - oar(o_podvalarray); - oar(o_iservalarray); - oar(o_isplvalarray); - oar(o_eservalarray); - oar(o_esplvalarray); - } - - std::valarray i_podvalarray; - std::valarray i_iservalarray; - std::valarray i_isplvalarray; - std::valarray i_eservalarray; - std::valarray i_esplvalarray; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podvalarray); - iar(i_iservalarray); - iar(i_isplvalarray); - iar(i_eservalarray); - iar(i_esplvalarray); - } - - BOOST_CHECK_EQUAL(i_podvalarray.size(), o_podvalarray.size()); - BOOST_CHECK_EQUAL(i_iservalarray.size(), o_iservalarray.size()); - BOOST_CHECK_EQUAL(i_isplvalarray.size(), o_isplvalarray.size()); - BOOST_CHECK_EQUAL(i_eservalarray.size(), o_eservalarray.size()); - BOOST_CHECK_EQUAL(i_esplvalarray.size(), o_esplvalarray.size()); - - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_podvalarray), std::end(i_podvalarray), std::begin(o_podvalarray), std::end(o_podvalarray)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_iservalarray), std::end(i_iservalarray), std::begin(o_iservalarray), std::end(o_iservalarray)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_isplvalarray), std::end(i_isplvalarray), std::begin(o_isplvalarray), std::end(o_isplvalarray)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_eservalarray), std::end(i_eservalarray), std::begin(o_eservalarray), std::end(o_eservalarray)); - BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_esplvalarray), std::end(i_esplvalarray), std::begin(o_esplvalarray), std::end(o_esplvalarray)); - } -} - -BOOST_AUTO_TEST_CASE(binary_valarray) +TEST_CASE("binary_valarray") { test_valarray(); } -BOOST_AUTO_TEST_CASE(portable_binary_valarray) +TEST_CASE("portable_binary_valarray") { test_valarray(); } -BOOST_AUTO_TEST_CASE(xml_valarray) +TEST_CASE("xml_valarray") { test_valarray(); } -BOOST_AUTO_TEST_CASE(json_valarray) +TEST_CASE("json_valarray") { test_valarray(); } + +TEST_SUITE_END(); diff --git a/unittests/valarray.hpp b/unittests/valarray.hpp new file mode 100644 index 000000000..19df153be --- /dev/null +++ b/unittests/valarray.hpp @@ -0,0 +1,101 @@ +/* +Copyright (c) 2014, Randolph Voorhies, Shane Grant +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +* Neither the name of cereal nor the +names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_VALARRAY_H_ +#define CEREAL_TEST_VALARRAY_H_ +#include "common.hpp" + +template inline +void test_valarray() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for (int ii = 0; ii<100; ++ii) + { + std::valarray o_podvalarray(100); + for (auto & elem : o_podvalarray) + elem = random_value(gen); + + std::valarray o_iservalarray(100); + for (auto & elem : o_iservalarray) + elem = StructInternalSerialize(random_value(gen), random_value(gen)); + + std::valarray o_isplvalarray(100); + for (auto & elem : o_isplvalarray) + elem = StructInternalSplit(random_value(gen), random_value(gen)); + + std::valarray o_eservalarray(100); + for (auto & elem : o_eservalarray) + elem = StructExternalSerialize(random_value(gen), random_value(gen)); + + std::valarray o_esplvalarray(100); + for (auto & elem : o_esplvalarray) + elem = StructExternalSplit(random_value(gen), random_value(gen)); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podvalarray); + oar(o_iservalarray); + oar(o_isplvalarray); + oar(o_eservalarray); + oar(o_esplvalarray); + } + + std::valarray i_podvalarray; + std::valarray i_iservalarray; + std::valarray i_isplvalarray; + std::valarray i_eservalarray; + std::valarray i_esplvalarray; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podvalarray); + iar(i_iservalarray); + iar(i_isplvalarray); + iar(i_eservalarray); + iar(i_esplvalarray); + } + + CHECK_EQ(i_podvalarray.size(), o_podvalarray.size()); + CHECK_EQ(i_iservalarray.size(), o_iservalarray.size()); + CHECK_EQ(i_isplvalarray.size(), o_isplvalarray.size()); + CHECK_EQ(i_eservalarray.size(), o_eservalarray.size()); + CHECK_EQ(i_esplvalarray.size(), o_esplvalarray.size()); + + check_collection(i_podvalarray , o_podvalarray ); + check_collection(i_iservalarray, o_iservalarray); + check_collection(i_isplvalarray, o_isplvalarray); + check_collection(i_eservalarray, o_eservalarray); + check_collection(i_esplvalarray, o_esplvalarray); + } +} + +#endif // CEREAL_TEST_VALARRAY_H_ diff --git a/unittests/vector.cpp b/unittests/vector.cpp index fdb686951..be172ba58 100644 --- a/unittests/vector.cpp +++ b/unittests/vector.cpp @@ -24,106 +24,29 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "vector.hpp" -template -void test_vector() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(int ii=0; ii<100; ++ii) - { - std::vector o_podvector(100); - for(auto & elem : o_podvector) - elem = random_value(gen); - - std::vector o_boolvector; o_boolvector.resize(100); - for( size_t i = 0; i < 100; ++i ) - o_boolvector[i] = (random_value(gen) % 2) == 0; - - std::vector o_iservector(100); - for(auto & elem : o_iservector) - elem = StructInternalSerialize( random_value(gen), random_value(gen) ); - - std::vector o_isplvector(100); - for(auto & elem : o_isplvector) - elem = StructInternalSplit( random_value(gen), random_value(gen) ); - - std::vector o_eservector(100); - for(auto & elem : o_eservector) - elem = StructExternalSerialize( random_value(gen), random_value(gen) ); - - std::vector o_esplvector(100); - for(auto & elem : o_esplvector) - elem = StructExternalSplit( random_value(gen), random_value(gen) ); - - std::ostringstream os; - { - OArchive oar(os); +TEST_SUITE("vector"); - oar(o_podvector); - oar(o_boolvector); - oar(o_iservector); - oar(o_isplvector); - oar(o_eservector); - oar(o_esplvector); - } - - std::vector i_podvector; - std::vector i_boolvector; - std::vector i_iservector; - std::vector i_isplvector; - std::vector i_eservector; - std::vector i_esplvector; - - std::istringstream is(os.str()); - { - IArchive iar(is); - - iar(i_podvector); - iar(i_boolvector); - iar(i_iservector); - iar(i_isplvector); - iar(i_eservector); - iar(i_esplvector); - } - - BOOST_CHECK_EQUAL(i_podvector.size(), o_podvector.size()); - BOOST_CHECK_EQUAL(i_boolvector.size(), o_boolvector.size()); - BOOST_CHECK_EQUAL(i_iservector.size(), o_iservector.size()); - BOOST_CHECK_EQUAL(i_isplvector.size(), o_isplvector.size()); - BOOST_CHECK_EQUAL(i_eservector.size(), o_eservector.size()); - BOOST_CHECK_EQUAL(i_esplvector.size(), o_esplvector.size()); - - BOOST_CHECK_EQUAL_COLLECTIONS(i_podvector.begin(), i_podvector.end(), o_podvector.begin(), o_podvector.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_boolvector.begin(), i_boolvector.end(), o_boolvector.begin(), o_boolvector.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_iservector.begin(), i_iservector.end(), o_iservector.begin(), o_iservector.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_isplvector.begin(), i_isplvector.end(), o_isplvector.begin(), o_isplvector.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_eservector.begin(), i_eservector.end(), o_eservector.begin(), o_eservector.end()); - BOOST_CHECK_EQUAL_COLLECTIONS(i_esplvector.begin(), i_esplvector.end(), o_esplvector.begin(), o_esplvector.end()); - } -} - -BOOST_AUTO_TEST_CASE( binary_vector ) +TEST_CASE("binary_vector") { test_vector(); } -BOOST_AUTO_TEST_CASE( portable_binary_vector ) +TEST_CASE("portable_binary_vector") { test_vector(); } -BOOST_AUTO_TEST_CASE( xml_vector ) +TEST_CASE("xml_vector") { test_vector(); } -BOOST_AUTO_TEST_CASE( json_vector ) +TEST_CASE("json_vector") { test_vector(); } - +TEST_SUITE_END(); diff --git a/unittests/vector.hpp b/unittests/vector.hpp new file mode 100644 index 000000000..a0297905b --- /dev/null +++ b/unittests/vector.hpp @@ -0,0 +1,110 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_VECTOR_H_ +#define CEREAL_TEST_VECTOR_H_ +#include "common.hpp" + +template inline +void test_vector() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for(int ii=0; ii<100; ++ii) + { + std::vector o_podvector(100); + for(auto & elem : o_podvector) + elem = random_value(gen); + + std::vector o_boolvector; o_boolvector.resize(100); + for( size_t i = 0; i < 100; ++i ) + o_boolvector[i] = (random_value(gen) % 2) == 0; + + std::vector o_iservector(100); + for(auto & elem : o_iservector) + elem = StructInternalSerialize( random_value(gen), random_value(gen) ); + + std::vector o_isplvector(100); + for(auto & elem : o_isplvector) + elem = StructInternalSplit( random_value(gen), random_value(gen) ); + + std::vector o_eservector(100); + for(auto & elem : o_eservector) + elem = StructExternalSerialize( random_value(gen), random_value(gen) ); + + std::vector o_esplvector(100); + for(auto & elem : o_esplvector) + elem = StructExternalSplit( random_value(gen), random_value(gen) ); + + std::ostringstream os; + { + OArchive oar(os); + + oar(o_podvector); + oar(o_boolvector); + oar(o_iservector); + oar(o_isplvector); + oar(o_eservector); + oar(o_esplvector); + } + + std::vector i_podvector; + std::vector i_boolvector; + std::vector i_iservector; + std::vector i_isplvector; + std::vector i_eservector; + std::vector i_esplvector; + + std::istringstream is(os.str()); + { + IArchive iar(is); + + iar(i_podvector); + iar(i_boolvector); + iar(i_iservector); + iar(i_isplvector); + iar(i_eservector); + iar(i_esplvector); + } + + CHECK_EQ(i_podvector.size(), o_podvector.size()); + CHECK_EQ(i_boolvector.size(), o_boolvector.size()); + CHECK_EQ(i_iservector.size(), o_iservector.size()); + CHECK_EQ(i_isplvector.size(), o_isplvector.size()); + CHECK_EQ(i_eservector.size(), o_eservector.size()); + CHECK_EQ(i_esplvector.size(), o_esplvector.size()); + + check_collection(i_podvector, o_podvector ); + check_collection(i_boolvector, o_boolvector); + check_collection(i_iservector, o_iservector); + check_collection(i_isplvector, o_isplvector); + check_collection(i_eservector, o_eservector); + check_collection(i_esplvector, o_esplvector); + } +} + +#endif // CEREAL_TEST_VECTOR_H_ diff --git a/unittests/versioning.cpp b/unittests/versioning.cpp index 218a0ea86..872742644 100644 --- a/unittests/versioning.cpp +++ b/unittests/versioning.cpp @@ -24,227 +24,51 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "common.hpp" -#include +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "versioning.hpp" -#if CEREAL_THREAD_SAFE -#include -static std::mutex boostTestMutex; -#endif - -namespace Nested -{ - struct NestedClass - { - int x; - - template - void serialize( Archive & ar ) - { ar( x ); } - }; -} - -CEREAL_CLASS_VERSION( Nested::NestedClass, 1 ) - -class VersionStructMS -{ - public: - bool x; - std::uint32_t v; - - private: - friend class cereal::access; - template - void serialize( Archive & ar, std::uint32_t const version ) - { - ar( x ); - v = version; - } -}; - -struct VersionStructMSP -{ - uint8_t x; - std::uint32_t v; - template - void save( Archive & ar, std::uint32_t const /*version*/ ) const - { - ar( x ); - } - - template - void load( Archive & ar, std::uint32_t const version ) - { - ar( x ); - v = version; - } -}; - -struct VersionStructNMS -{ - std::int32_t x; - std::uint32_t v; -}; - -template -void serialize( Archive & ar, VersionStructNMS & vnms, const std::uint32_t version ) -{ - ar( vnms.x ); - vnms.v = version; -} - -struct VersionStructNMSP -{ - double x; - std::uint32_t v; -}; - -template -void save( Archive & ar, VersionStructNMSP const & vnms, const std::uint32_t /*version*/ ) -{ - ar( vnms.x ); -} - -template -void load( Archive & ar, VersionStructNMSP & vnms, const std::uint32_t version ) -{ - ar( vnms.x ); - vnms.v = version; -} - -CEREAL_CLASS_VERSION( VersionStructMSP, 33 ) -CEREAL_CLASS_VERSION( VersionStructNMS, 66 ) -CEREAL_CLASS_VERSION( VersionStructNMSP, 99 ) +TEST_SUITE("versioning"); -template -void test_versioning() -{ - std::random_device rd; - std::mt19937 gen(rd()); - - for(size_t i=0; i<100; ++i) - { - VersionStructMS o_MS = {random_value(gen) % 2 ? true : false, 1}; - VersionStructMSP o_MSP = {random_value(gen), 1}; - VersionStructNMS o_NMS = {random_value(gen), 1}; - VersionStructNMSP o_NMSP = {random_value(gen), 1}; - VersionStructMS o_MS2 = {random_value(gen) % 2 ? true : false, 1}; - VersionStructMSP o_MSP2 = {random_value(gen), 1}; - VersionStructNMS o_NMS2 = {random_value(gen), 1}; - VersionStructNMSP o_NMSP2 = {random_value(gen), 1}; - - std::ostringstream os; - { - OArchive oar(os); - oar( o_MS ); - oar( o_MSP ); - oar( o_NMS ); - oar( o_NMSP ); - oar( o_MS2 ); - oar( o_MSP2 ); - oar( o_NMS2 ); - oar( o_NMSP2 ); - } - - decltype(o_MS) i_MS; - decltype(o_MSP) i_MSP; - decltype(o_NMS) i_NMS; - decltype(o_NMSP) i_NMSP; - decltype(o_MS2) i_MS2; - decltype(o_MSP2) i_MSP2; - decltype(o_NMS2) i_NMS2; - decltype(o_NMSP2) i_NMSP2; - - std::istringstream is(os.str()); - { - IArchive iar(is); - iar( i_MS ); - iar( i_MSP ); - iar( i_NMS ); - iar( i_NMSP ); - iar( i_MS2 ); - iar( i_MSP2 ); - iar( i_NMS2 ); - iar( i_NMSP2 ); - } - - #if CEREAL_THREAD_SAFE - std::lock_guard lock( boostTestMutex ); - #endif - - BOOST_CHECK_EQUAL(o_MS.x, i_MS.x); - BOOST_CHECK_EQUAL(i_MS.v, 0u); - BOOST_CHECK_EQUAL(o_MSP.x, i_MSP.x); - BOOST_CHECK_EQUAL(i_MSP.v, 33u); - BOOST_CHECK_EQUAL(o_NMS.x, i_NMS.x); - BOOST_CHECK_EQUAL(i_NMS.v, 66u); - BOOST_CHECK_CLOSE(o_NMSP.x, i_NMSP.x, 1e-5); - BOOST_CHECK_EQUAL(i_NMSP.v, 99u); - - BOOST_CHECK_EQUAL(o_MS2.x, i_MS2.x); - BOOST_CHECK_EQUAL(i_MS2.v, 0u); - BOOST_CHECK_EQUAL(o_MSP2.x, i_MSP2.x); - BOOST_CHECK_EQUAL(i_MSP2.v, 33u); - BOOST_CHECK_EQUAL(o_NMS2.x, i_NMS2.x); - BOOST_CHECK_EQUAL(i_NMS2.v, 66u); - BOOST_CHECK_CLOSE(o_NMSP2.x, i_NMSP2.x, 1e-5); - BOOST_CHECK_EQUAL(i_NMSP2.v, 99u); - } -} - -BOOST_AUTO_TEST_CASE( binary_versioning ) +TEST_CASE("binary_versioning") { test_versioning(); } -BOOST_AUTO_TEST_CASE( portable_binary_versioning ) +TEST_CASE("portable_binary_versioning") { test_versioning(); } -BOOST_AUTO_TEST_CASE( xml_versioning ) +TEST_CASE("xml_versioning") { test_versioning(); } -BOOST_AUTO_TEST_CASE( json_versioning ) +TEST_CASE("json_versioning") { test_versioning(); } #if CEREAL_THREAD_SAFE -template -void test_versioning_threading() -{ - std::vector> pool; - for( size_t i = 0; i < 100; ++i ) - pool.emplace_back( std::async( std::launch::async, - [](){ test_versioning(); return true; } ) ); - - for( auto & future : pool ) - future.wait(); - - for( auto & future : pool ) - BOOST_CHECK( future.get() == true ); -} - -BOOST_AUTO_TEST_CASE( binary_versioning_threading ) +TEST_CASE("binary_versioning_threading") { test_versioning_threading(); } -BOOST_AUTO_TEST_CASE( portable_binary_versioning_threading ) +TEST_CASE("portable_binary_versioning_threading") { test_versioning_threading(); } -BOOST_AUTO_TEST_CASE( xml_versioning_threading ) +TEST_CASE("xml_versioning_threading") { test_versioning_threading(); } -BOOST_AUTO_TEST_CASE( json_versioning_threading ) +TEST_CASE("json_versioning_threading") { test_versioning_threading(); } #endif // CEREAL_THREAD_SAFE + +TEST_SUITE_END(); diff --git a/unittests/versioning.hpp b/unittests/versioning.hpp new file mode 100644 index 000000000..33e21d261 --- /dev/null +++ b/unittests/versioning.hpp @@ -0,0 +1,217 @@ +/* + Copyright (c) 2014, Randolph Voorhies, Shane Grant + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of cereal nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef CEREAL_TEST_VERSIONING_H_ +#define CEREAL_TEST_VERSIONING_H_ +#include "common.hpp" + +#if CEREAL_THREAD_SAFE +#include +#endif + +namespace Nested +{ + struct NestedClass + { + int x; + + template + void serialize( Archive & ar ) + { ar( x ); } + }; +} + +CEREAL_CLASS_VERSION( Nested::NestedClass, 1 ) + +class VersionStructMS +{ + public: + bool x; + std::uint32_t v; + + private: + friend class cereal::access; + template + void serialize( Archive & ar, std::uint32_t const version ) + { + ar( x ); + v = version; + } +}; + +struct VersionStructMSP +{ + uint8_t x; + std::uint32_t v; + template + void save( Archive & ar, std::uint32_t const /*version*/ ) const + { + ar( x ); + } + + template + void load( Archive & ar, std::uint32_t const version ) + { + ar( x ); + v = version; + } +}; + +struct VersionStructNMS +{ + std::int32_t x; + std::uint32_t v; +}; + +template +void serialize( Archive & ar, VersionStructNMS & vnms, const std::uint32_t version ) +{ + ar( vnms.x ); + vnms.v = version; +} + +struct VersionStructNMSP +{ + double x; + std::uint32_t v; +}; + +template +void save( Archive & ar, VersionStructNMSP const & vnms, const std::uint32_t /*version*/ ) +{ + ar( vnms.x ); +} + +template +void load( Archive & ar, VersionStructNMSP & vnms, const std::uint32_t version ) +{ + ar( vnms.x ); + vnms.v = version; +} + +CEREAL_CLASS_VERSION( VersionStructMSP, 33 ) +CEREAL_CLASS_VERSION( VersionStructNMS, 66 ) +CEREAL_CLASS_VERSION( VersionStructNMSP, 99 ) + +template inline +void test_versioning() +{ + std::random_device rd; + std::mt19937 gen(rd()); + + #if CEREAL_THREAD_SAFE + #include + static std::mutex testMutex; + #endif + + for(size_t i=0; i<100; ++i) + { + VersionStructMS o_MS = {random_value(gen) % 2 ? true : false, 1}; + VersionStructMSP o_MSP = {random_value(gen), 1}; + VersionStructNMS o_NMS = {random_value(gen), 1}; + VersionStructNMSP o_NMSP = {random_value(gen), 1}; + VersionStructMS o_MS2 = {random_value(gen) % 2 ? true : false, 1}; + VersionStructMSP o_MSP2 = {random_value(gen), 1}; + VersionStructNMS o_NMS2 = {random_value(gen), 1}; + VersionStructNMSP o_NMSP2 = {random_value(gen), 1}; + + std::ostringstream os; + { + OArchive oar(os); + oar( o_MS ); + oar( o_MSP ); + oar( o_NMS ); + oar( o_NMSP ); + oar( o_MS2 ); + oar( o_MSP2 ); + oar( o_NMS2 ); + oar( o_NMSP2 ); + } + + decltype(o_MS) i_MS; + decltype(o_MSP) i_MSP; + decltype(o_NMS) i_NMS; + decltype(o_NMSP) i_NMSP; + decltype(o_MS2) i_MS2; + decltype(o_MSP2) i_MSP2; + decltype(o_NMS2) i_NMS2; + decltype(o_NMSP2) i_NMSP2; + + std::istringstream is(os.str()); + { + IArchive iar(is); + iar( i_MS ); + iar( i_MSP ); + iar( i_NMS ); + iar( i_NMSP ); + iar( i_MS2 ); + iar( i_MSP2 ); + iar( i_NMS2 ); + iar( i_NMSP2 ); + } + + #if CEREAL_THREAD_SAFE + std::lock_guard lock( testMutex ); + #endif + + CHECK_EQ(o_MS.x, i_MS.x); + CHECK_EQ(i_MS.v, 0u); + CHECK_EQ(o_MSP.x, i_MSP.x); + CHECK_EQ(i_MSP.v, 33u); + CHECK_EQ(o_NMS.x, i_NMS.x); + CHECK_EQ(i_NMS.v, 66u); + CHECK_EQ(o_NMSP.x, doctest::Approx(i_NMSP.x).epsilon(1e-5)); + CHECK_EQ(i_NMSP.v, 99u); + + CHECK_EQ(o_MS2.x, i_MS2.x); + CHECK_EQ(i_MS2.v, 0u); + CHECK_EQ(o_MSP2.x, i_MSP2.x); + CHECK_EQ(i_MSP2.v, 33u); + CHECK_EQ(o_NMS2.x, i_NMS2.x); + CHECK_EQ(i_NMS2.v, 66u); + CHECK_EQ(o_NMSP2.x, doctest::Approx(i_NMSP2.x).epsilon(1e-5)); + CHECK_EQ(i_NMSP2.v, 99u); + } +} + +#if CEREAL_THREAD_SAFE +template inline +void test_versioning_threading() +{ + std::vector> pool; + for( size_t i = 0; i < 100; ++i ) + pool.emplace_back( std::async( std::launch::async, + [](){ test_versioning(); return true; } ) ); + + for( auto & future : pool ) + future.wait(); + + for( auto & future : pool ) + CHECK_UNARY( future.get() ); +} +#endif // CEREAL_THREAD_SAFE + +#endif // CEREAL_TEST_VERSIONING_H_