mirror of
https://github.com/NGSolve/netgen.git
synced 2024-11-11 16:49:16 +05:00
archive works for pointers and shared_ptrs (even with
mult. inheritance and virtual base classes)
This commit is contained in:
parent
7bfc48e8f3
commit
8e29d38fc1
@ -17,6 +17,7 @@ option( INTEL_MIC "cross compile for intel xeon phi")
|
||||
option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
|
||||
option( USE_CCACHE "use ccache")
|
||||
option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON)
|
||||
option( ENABLE_UNIT_TESTS "Enable Catch unit tests")
|
||||
|
||||
option( USE_SUPERBUILD "use ccache" ON)
|
||||
|
||||
@ -341,6 +342,11 @@ execute_process(COMMAND hdiutil create -volname Netgen -srcfolder ${CMAKE_INSTAL
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
|
||||
if(ENABLE_UNIT_TESTS)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/external_projects/catch.cmake)
|
||||
endif(ENABLE_UNIT_TESTS)
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
add_subdirectory(libsrc)
|
||||
|
@ -140,6 +140,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
||||
INTEL_MIC
|
||||
CMAKE_PREFIX_PATH
|
||||
CMAKE_INSTALL_PREFIX
|
||||
ENABLE_UNIT_TESTS
|
||||
)
|
||||
|
||||
# propagate all variables set on the command line using cmake -DFOO=BAR
|
||||
|
18
cmake/external_projects/catch.cmake
Normal file
18
cmake/external_projects/catch.cmake
Normal file
@ -0,0 +1,18 @@
|
||||
include (ExternalProject)
|
||||
find_program(GIT_EXECUTABLE git)
|
||||
ExternalProject_Add(
|
||||
project_catch
|
||||
PREFIX ${CMAKE_BINARY_DIR}/catch
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v2.0.1
|
||||
TIMEOUT 10
|
||||
UPDATE_COMMAND "" # ${GIT_EXECUTABLE} pull
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD ON
|
||||
)
|
||||
|
||||
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
||||
ExternalProject_Get_Property(project_catch source_dir)
|
||||
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
@ -1,8 +1,10 @@
|
||||
add_definitions(-DNGINTERFACE_EXPORTS)
|
||||
add_library(ngcore OBJECT basearchive.cpp)
|
||||
add_library(ngcore basearchive.cpp)
|
||||
|
||||
set_target_properties(ngcore PROPERTIES POSITION_INDEPENDENT_CODE ON )
|
||||
|
||||
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
||||
|
||||
install(FILES ngcore.hpp archive.hpp basearchive.hpp
|
||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel
|
||||
)
|
||||
|
@ -16,6 +16,7 @@ namespace ngcore
|
||||
: BinaryOutArchive(std::make_shared<std::ofstream>(filename)) {}
|
||||
virtual ~BinaryOutArchive () { FlushBuffer(); }
|
||||
|
||||
using Archive::operator&;
|
||||
virtual Archive & operator & (double & d)
|
||||
{ return Write(d); }
|
||||
virtual Archive & operator & (int & i)
|
||||
@ -81,6 +82,7 @@ namespace ngcore
|
||||
BinaryInArchive (std::string filename)
|
||||
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) {}
|
||||
|
||||
using Archive::operator&;
|
||||
virtual Archive & operator & (double & d)
|
||||
{ Read(d); return *this; }
|
||||
virtual Archive & operator & (int & i)
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
std::map<std::string, std::function<void*()>>& GetArchiveRegister()
|
||||
std::map<std::string, ClassArchiveInfo>& GetArchiveRegister()
|
||||
{
|
||||
static std::map<std::string, std::function<void*()>> type_register = {};
|
||||
static std::map<std::string, ClassArchiveInfo> type_register;
|
||||
return type_register;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,31 @@ namespace ngcore
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
std::map<std::string, std::function<void*()>>& GetArchiveRegister();
|
||||
// Info stored by registering a class using the RegisterClassForArchive struct in the map
|
||||
// stored in GetArchiveRegister
|
||||
struct ClassArchiveInfo
|
||||
{
|
||||
// create new object of this type and return a void* pointer that is points to the location
|
||||
// of the (base)class given by type_info
|
||||
std::function<void*(const std::type_info&)> creator;
|
||||
// This caster takes a void* pointer to the type stored in this info and casts it to a
|
||||
// void* pointer pointing to the (base)class type_info
|
||||
std::function<void*(const std::type_info&, void*)> upcaster;
|
||||
// This caster takes a void* pointer to the (base)class type_info and returns void* pointing
|
||||
// to the type stored in this info
|
||||
std::function<void*(const std::type_info&, void*)> downcaster;
|
||||
};
|
||||
|
||||
// Returns a map of from the mangled typeids to the ClassArchiveInfo
|
||||
std::map<std::string, ClassArchiveInfo>& GetArchiveRegister();
|
||||
|
||||
// Helper class for up-/downcasting
|
||||
template<typename T, typename ... Bases>
|
||||
struct Caster
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p);
|
||||
static void* tryDowncast(const std::type_info& ti, void* p);
|
||||
};
|
||||
|
||||
// Base Archive class
|
||||
class Archive
|
||||
@ -76,11 +100,12 @@ namespace ngcore
|
||||
size = v.size();
|
||||
(*this) & size;
|
||||
if(!is_output)
|
||||
v.reserve(size);
|
||||
v.resize(size);
|
||||
Do(&v[0], size);
|
||||
return (*this);
|
||||
}
|
||||
// Archive arrays =====================================================
|
||||
// this functions can be overloaded in Archive implementations for more efficiency
|
||||
template <typename T>
|
||||
Archive & Do (T * data, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; };
|
||||
@ -122,32 +147,87 @@ namespace ngcore
|
||||
// save -2 for nullptr
|
||||
if(!ptr)
|
||||
return (*this) << -2;
|
||||
auto pos = shared_ptr2nr.find((void*) ptr.get());
|
||||
|
||||
void* reg_ptr = ptr.get();
|
||||
bool neededDowncast = false;
|
||||
if constexpr(has_DoArchive<T>::value)
|
||||
{
|
||||
if(GetArchiveRegister().count(std::string(typeid(*ptr).name())) == 0)
|
||||
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
||||
+ typeid(*ptr).name()
|
||||
+ " not registered for archive");
|
||||
else
|
||||
reg_ptr = GetArchiveRegister()[typeid(*ptr).name()].downcaster(typeid(T), ptr.get());
|
||||
if(reg_ptr != (void*) ptr.get())
|
||||
neededDowncast = true;
|
||||
}
|
||||
auto pos = shared_ptr2nr.find(reg_ptr);
|
||||
// if not found store -1 and the pointer
|
||||
if(pos == shared_ptr2nr.end())
|
||||
{
|
||||
shared_ptr2nr[(void*) ptr.get()] = shared_ptr_count++;
|
||||
auto p = ptr.get();
|
||||
return (*this) << -1 & p;
|
||||
(*this) << -1;
|
||||
(*this) & neededDowncast & p;
|
||||
if(neededDowncast)
|
||||
(*this) << std::string(typeid(*ptr).name());
|
||||
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
||||
return *this;
|
||||
}
|
||||
// if found store the position
|
||||
return (*this) << pos->second;
|
||||
// if found store the position and if it has to be downcasted and how
|
||||
(*this) << pos->second << neededDowncast;
|
||||
if(neededDowncast)
|
||||
(*this) << std::string(typeid(*ptr).name());
|
||||
return (*this);
|
||||
}
|
||||
else // Input
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
if(nr == -2)
|
||||
{
|
||||
ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
else if (nr == -1)
|
||||
{
|
||||
T* p;
|
||||
(*this) & p;
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast & p;
|
||||
ptr = std::shared_ptr<T>(p);
|
||||
if(neededDowncast)
|
||||
{
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
auto info = GetArchiveRegister()[name];
|
||||
nr2shared_ptr.push_back(std::shared_ptr<void>(std::static_pointer_cast<void>(ptr),
|
||||
info.downcaster(typeid(T),
|
||||
ptr.get())));
|
||||
}
|
||||
else
|
||||
nr2shared_ptr.push_back(ptr);
|
||||
}
|
||||
else
|
||||
ptr = std::reinterpret_pointer_cast<T>(nr2shared_ptr[nr]);
|
||||
{
|
||||
auto other = nr2shared_ptr[nr];
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast;
|
||||
if(neededDowncast)
|
||||
{
|
||||
if constexpr(has_DoArchive<T>::value)
|
||||
{
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
auto info = GetArchiveRegister()[name];
|
||||
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
||||
info.upcaster(typeid(T),
|
||||
other.get())));
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Shouldn't get here...");
|
||||
}
|
||||
else
|
||||
ptr = std::static_pointer_cast<T>(other);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -165,11 +245,21 @@ namespace ngcore
|
||||
(*this) & m2;
|
||||
return *this;
|
||||
}
|
||||
auto pos = ptr2nr.find( (void*) p);
|
||||
void* reg_ptr = (void*)p;
|
||||
if constexpr(has_DoArchive<T>::value)
|
||||
{
|
||||
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
||||
+ typeid(*p).name()
|
||||
+ " not registered for archive");
|
||||
else
|
||||
reg_ptr = GetArchiveRegister()[typeid(*p).name()].downcaster(typeid(T), p);
|
||||
}
|
||||
auto pos = ptr2nr.find(reg_ptr);
|
||||
// if the pointer is not found in the map create a new entry
|
||||
if (pos == ptr2nr.end())
|
||||
{
|
||||
ptr2nr[(void*) p] = ptr_count++;
|
||||
ptr2nr[reg_ptr] = ptr_count++;
|
||||
if(typeid(*p) == typeid(T))
|
||||
if constexpr (std::is_constructible<T>::value)
|
||||
{
|
||||
@ -183,7 +273,7 @@ namespace ngcore
|
||||
// We want this special behaviour only for our classes that implement DoArchive
|
||||
if constexpr(has_DoArchive<T>::value)
|
||||
{
|
||||
if(GetArchiveRegister().count(typeid(*p).name()) == 0)
|
||||
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
||||
+ typeid(*p).name()
|
||||
+ " not registered for archive");
|
||||
@ -199,13 +289,13 @@ namespace ngcore
|
||||
else
|
||||
{
|
||||
(*this) & pos->second;
|
||||
(*this) << std::string(typeid(*p).name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
// cout << "in, got nr " << nr << endl;
|
||||
if (nr == -2)
|
||||
{
|
||||
p = nullptr;
|
||||
@ -215,9 +305,8 @@ namespace ngcore
|
||||
if constexpr (std::is_constructible<T>::value)
|
||||
{
|
||||
p = new T;
|
||||
// cout << "create new ptr, p = " << p << endl;
|
||||
(*this) & *p;
|
||||
nr2ptr.push_back(p);
|
||||
(*this) & *p;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Class isn't registered properly");
|
||||
@ -230,16 +319,25 @@ namespace ngcore
|
||||
{
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
p = reinterpret_cast<T*>(GetArchiveRegister()[name]());
|
||||
nr2ptr.push_back(p);
|
||||
auto info = GetArchiveRegister()[name];
|
||||
p = (T*) info.creator(typeid(T));
|
||||
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
||||
(*this) & *p;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Class isn't registered properly");
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (T*)nr2ptr[nr];
|
||||
// cout << "reuse ptr " << nr << ": " << p << endl;
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
if constexpr(has_DoArchive<T>::value)
|
||||
{
|
||||
auto info = GetArchiveRegister()[name];
|
||||
p = (T*) info.upcaster(typeid(T), nr2ptr[nr]);
|
||||
}
|
||||
else
|
||||
p = (T*) nr2ptr[nr];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
@ -253,14 +351,62 @@ namespace ngcore
|
||||
(*this) & ht;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void FlushBuffer() {}
|
||||
};
|
||||
|
||||
template<typename T, typename ... Bases>
|
||||
class RegisterClassForArchive
|
||||
{
|
||||
public:
|
||||
RegisterClassForArchive()
|
||||
{
|
||||
static_assert(std::is_constructible_v<T>, "Class registered for archive must be default constructible");
|
||||
ClassArchiveInfo info;
|
||||
info.creator = [this,&info](const std::type_info& ti) -> void*
|
||||
{ return typeid(T) == ti ? new T : Caster<T, Bases...>::tryUpcast(ti, new T); };
|
||||
info.upcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryUpcast(ti, (T*) p); };
|
||||
info.downcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryDowncast(ti, p); };
|
||||
GetArchiveRegister()[std::string(typeid(T).name())] = info;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void RegisterClassForArchive()
|
||||
struct Caster<T>
|
||||
{
|
||||
static_assert(std::is_constructible_v<T>, "Class registered for archive must be default constructible");
|
||||
GetArchiveRegister()[std::string(typeid(T).name())] = []() -> void* { return new T; };
|
||||
static void* tryUpcast (const std::type_info& ti, T* p)
|
||||
{
|
||||
throw std::runtime_error("Upcast not successful, some classes are not registered properly for archiving!");
|
||||
}
|
||||
static void* tryDowncast (const std::type_info& ti, void* p)
|
||||
{
|
||||
throw std::runtime_error("Downcast not successful, some classes are not registered properly for archiving!");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename B1, typename ... Brest>
|
||||
struct Caster<T,B1,Brest...>
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p)
|
||||
{
|
||||
try
|
||||
{ return GetArchiveRegister()[typeid(B1).name()].upcaster(ti, (void*) (dynamic_cast<B1*>(p))); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryUpcast(ti, p); }
|
||||
}
|
||||
|
||||
static void* tryDowncast(const std::type_info& ti, void* p)
|
||||
{
|
||||
if(typeid(B1) == ti)
|
||||
return dynamic_cast<T*>((B1*) p);
|
||||
try
|
||||
{ return GetArchiveRegister()[typeid(B1).name()].downcaster(ti, (void*) ((B1*)p)); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryDowncast(ti, p); }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NG_BASEARCHIVE_HPP
|
||||
|
@ -4,7 +4,6 @@ if(NOT WIN32)
|
||||
$<TARGET_OBJECTS:la>
|
||||
$<TARGET_OBJECTS:gprim>
|
||||
$<TARGET_OBJECTS:gen>
|
||||
$<TARGET_OBJECTS:ngcore>
|
||||
)
|
||||
endif(NOT WIN32)
|
||||
|
||||
@ -31,7 +30,7 @@ if(APPLE)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT WIN32)
|
||||
target_link_libraries( mesh ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
|
||||
target_link_libraries( mesh ngcore ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
|
||||
install( TARGETS mesh ${NG_INSTALL_DIR})
|
||||
endif(NOT WIN32)
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
add_subdirectory(catch)
|
||||
add_subdirectory(pytest)
|
||||
|
30
tests/catch/CMakeLists.txt
Normal file
30
tests/catch/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
if(ENABLE_UNIT_TESTS)
|
||||
add_custom_target(unit_tests)
|
||||
|
||||
# Build catch_main test object
|
||||
message("netgen include dir = ${NETGEN_INCLUDE_DIR_ABSOLUTE} --------------------------------------")
|
||||
include_directories(${CATCH_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/include})
|
||||
add_library(catch_main STATIC main.cpp)
|
||||
set_target_properties(catch_main PROPERTIES CXX_STANDARD 17)
|
||||
add_dependencies(unit_tests catch_main)
|
||||
add_dependencies(catch_main project_catch)
|
||||
|
||||
# ensure the test targets are built before testing
|
||||
add_test(NAME unit_tests_built COMMAND ${CMAKE_COMMAND} --build . --target unit_tests --config ${CMAKE_BUILD_TYPE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../.. )
|
||||
|
||||
macro(add_unit_test name sources)
|
||||
add_executable(test_${name} ${sources} )
|
||||
if (WIN32)
|
||||
target_link_libraries(test_${name} ngcore catch_main)
|
||||
else(WIN32)
|
||||
target_link_libraries(test_${name} ngcore catch_main)
|
||||
endif(WIN32)
|
||||
|
||||
add_dependencies(unit_tests test_${name})
|
||||
add_test(NAME unit_${name} COMMAND test_${name})
|
||||
set_tests_properties(unit_${name} PROPERTIES DEPENDS unit_tests_built)
|
||||
endmacro()
|
||||
|
||||
add_unit_test(archive archive.cpp)
|
||||
endif(ENABLE_UNIT_TESTS)
|
176
tests/catch/archive.cpp
Normal file
176
tests/catch/archive.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <../core/ngcore.hpp>
|
||||
using namespace ngcore;
|
||||
using namespace std;
|
||||
|
||||
class CommonBase
|
||||
{
|
||||
public:
|
||||
virtual ~CommonBase() {}
|
||||
|
||||
virtual void DoArchive(Archive& archive) { }
|
||||
};
|
||||
|
||||
class SharedPtrHolder : virtual public CommonBase
|
||||
{
|
||||
public:
|
||||
vector<shared_ptr<string>> names;
|
||||
virtual ~SharedPtrHolder()
|
||||
{ }
|
||||
|
||||
virtual void DoArchive(Archive& archive) { archive & names; }
|
||||
};
|
||||
|
||||
class PtrHolder : virtual public CommonBase
|
||||
{
|
||||
public:
|
||||
vector<int*> numbers;
|
||||
virtual ~PtrHolder() {}
|
||||
|
||||
virtual void DoArchive(Archive& archive) { archive & numbers; }
|
||||
};
|
||||
|
||||
class SharedPtrAndPtrHolder : public SharedPtrHolder, public PtrHolder
|
||||
{
|
||||
public:
|
||||
virtual ~SharedPtrAndPtrHolder() {}
|
||||
virtual void DoArchive(Archive& archive)
|
||||
{
|
||||
SharedPtrHolder::DoArchive(archive);
|
||||
PtrHolder::DoArchive(archive);
|
||||
}
|
||||
};
|
||||
|
||||
class NotRegisteredForArchive : public SharedPtrAndPtrHolder {};
|
||||
|
||||
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {};
|
||||
|
||||
static RegisterClassForArchive<CommonBase> regb;
|
||||
static RegisterClassForArchive<SharedPtrHolder, CommonBase> regsp;
|
||||
static RegisterClassForArchive<PtrHolder, CommonBase> regp;
|
||||
static RegisterClassForArchive<SharedPtrAndPtrHolder, SharedPtrHolder, PtrHolder> regspp;
|
||||
static RegisterClassForArchive<OneMoreDerivedClass, SharedPtrAndPtrHolder> regom;
|
||||
|
||||
void testSharedPointer(Archive& in, Archive& out)
|
||||
{
|
||||
SECTION("Same shared ptr")
|
||||
{
|
||||
static_assert(has_DoArchive<SharedPtrHolder>::value, "");
|
||||
SharedPtrHolder holder, holder2;
|
||||
holder.names.push_back(make_shared<string>("name"));
|
||||
holder2.names = holder.names; // same shared ptr
|
||||
out & holder & holder2;
|
||||
out.FlushBuffer();
|
||||
SharedPtrHolder inholder, inholder2;
|
||||
in & inholder & inholder2;
|
||||
CHECK(inholder.names.size() == 1);
|
||||
CHECK(inholder.names[0] == inholder2.names[0]);
|
||||
CHECK(inholder.names[0].use_count() == 3); // one shared ptr is still kept in the archive
|
||||
CHECK(*inholder.names[0] == "name");
|
||||
}
|
||||
}
|
||||
|
||||
void testPointer(Archive& in, Archive& out)
|
||||
{
|
||||
SECTION("Same pointer")
|
||||
{
|
||||
PtrHolder holder, holder2;
|
||||
holder.numbers.push_back(new int(3));
|
||||
holder2.numbers = holder.numbers; // same shared ptr
|
||||
out & holder & holder2;
|
||||
out.FlushBuffer();
|
||||
PtrHolder inholder, inholder2;
|
||||
in & inholder & inholder2;
|
||||
CHECK(inholder.numbers.size() == 1);
|
||||
CHECK(inholder.numbers[0] == inholder2.numbers[0]);
|
||||
CHECK(*inholder.numbers[0] == 3);
|
||||
}
|
||||
}
|
||||
|
||||
void testMultipleInheritance(Archive& in, Archive& out)
|
||||
{
|
||||
PtrHolder* p = new OneMoreDerivedClass;
|
||||
p->numbers.push_back(new int(2));
|
||||
auto p2 = dynamic_cast<SharedPtrHolder*>(p);
|
||||
p2->names.push_back(make_shared<string>("test"));
|
||||
auto sp1 = shared_ptr<PtrHolder>(p);
|
||||
auto sp2 = dynamic_pointer_cast<SharedPtrHolder>(sp1);
|
||||
auto checkPtr = [] (auto pin, auto pin2)
|
||||
{
|
||||
CHECK(typeid(*pin) == typeid(*pin2));
|
||||
CHECK(typeid(*pin) == typeid(OneMoreDerivedClass));
|
||||
CHECK(*pin2->names[0] == "test");
|
||||
CHECK(*pin->numbers[0] == 2);
|
||||
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin) == dynamic_cast<SharedPtrAndPtrHolder*>(pin2));
|
||||
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin2) != nullptr);
|
||||
CHECK(*dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0] == 2);
|
||||
CHECK(*pin->numbers[0] == *dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0]);
|
||||
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin) != nullptr);
|
||||
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin)->names[0] == pin2->names[0]);
|
||||
};
|
||||
SECTION("Archive ptrs to leaves of mult. inh.")
|
||||
{
|
||||
out & p & p2;
|
||||
out.FlushBuffer();
|
||||
PtrHolder* pin;
|
||||
SharedPtrHolder* pin2;
|
||||
in & pin & pin2;
|
||||
checkPtr(pin, pin2);
|
||||
}
|
||||
SECTION("Archive shared ptrs to leaves of mult. inh.")
|
||||
{
|
||||
out & sp1 & sp2;
|
||||
out.FlushBuffer();
|
||||
shared_ptr<PtrHolder> pin;
|
||||
shared_ptr<SharedPtrHolder> pin2;
|
||||
in & pin & pin2;
|
||||
checkPtr(pin.get(), pin2.get());
|
||||
}
|
||||
SECTION("Virtual base class")
|
||||
{
|
||||
CommonBase* b = dynamic_cast<CommonBase*>(p);
|
||||
out & b & p;
|
||||
PtrHolder* pin;
|
||||
CommonBase* bin;
|
||||
in & bin & pin;
|
||||
checkPtr(pin, dynamic_cast<SharedPtrHolder*>(bin));
|
||||
}
|
||||
}
|
||||
|
||||
void testArchive(Archive& in, Archive& out)
|
||||
{
|
||||
SECTION("SharedPtr")
|
||||
{
|
||||
testSharedPointer(in, out);
|
||||
}
|
||||
SECTION("Pointer")
|
||||
{
|
||||
testPointer(in, out);
|
||||
}
|
||||
SECTION("Multiple inheritance")
|
||||
{
|
||||
testMultipleInheritance(in, out);
|
||||
}
|
||||
SECTION("Not registered")
|
||||
{
|
||||
SharedPtrAndPtrHolder* p = new NotRegisteredForArchive;
|
||||
REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("BinaryArchive")
|
||||
{
|
||||
auto stream = make_shared<stringstream>();
|
||||
BinaryOutArchive out(stream);
|
||||
BinaryInArchive in(stream);
|
||||
testArchive(in, out);
|
||||
}
|
||||
|
||||
TEST_CASE("TextArchive")
|
||||
{
|
||||
auto stream = make_shared<stringstream>();
|
||||
TextOutArchive out(stream);
|
||||
TextInArchive in(stream);
|
||||
testArchive(in, out);
|
||||
}
|
3
tests/catch/main.cpp
Normal file
3
tests/catch/main.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
Loading…
Reference in New Issue
Block a user