From 9118afdd13df2215c25aaed1438520e0e79b8f07 Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Wed, 1 Apr 2026 19:59:37 +0000 Subject: [PATCH] fix serialization for properties unintrusive --- docs/archives.md | 84 +++++++++ src/Core/Archives.h | 164 ++++++----------- src/Core/Property.h | 24 ++- src/Core/Serializable.h | 5 + src/Core/testing/PropertiesTest.cpp | 171 ++++++++++++------ .../testing/SerializeDreadDiamondTest.cpp | 37 +++- src/Core/testing/SerializeTest.cpp | 9 +- 7 files changed, 312 insertions(+), 182 deletions(-) create mode 100644 docs/archives.md diff --git a/docs/archives.md b/docs/archives.md new file mode 100644 index 0000000..7e60bfc --- /dev/null +++ b/docs/archives.md @@ -0,0 +1,84 @@ +# Serialization and Archives Internals + +This document explains the internal design of the `uLib` serialization system, which is built on top of **Boost.Serialization**. It provides custom archive implementations for various formats (XML, Text, Logging) and introduces **Human Readable Pairs (HRP)** for metadata-rich serialization. + +--- + +## Architecture Overview + +The `uLib` archive system extends the standard `boost::archive` templates to add domain-specific features. The main components are: + +1. **Custom Interface Layer**: Extends the default Boost archive API with additional operators and utilities. +2. **Specialized Archive Implementations**: Specialized classes for XML, Text, and Logging. +3. **HRP Support**: First-class support for `hrp` (Human Readable Pair) wrappers, which carry units, ranges, and descriptions. +4. **Static Registration System**: Macros and explicit instantiations to handle polymorphic types and compilation isolation. + +--- + +## Custom Interface Layer + +All `uLib` archives use a custom interface defined in `Archives.h` via `uLib_interface_iarchive` and `uLib_interface_oarchive`. These templates add several key features: + +| Feature | Operator/Method | Description | +|---|---|---| +| **Mapping Operator** | `operator==` | Aliased to `operator&` (Boost's standard mapping operator). | +| **Trace Operator** | `operator!=` | Used for trace/debug output of strings during serialization. | +| **Type Registration** | `register_type()` | Registers a class type with the archive's internal serializer map. | +| **Standard IO** | `operator<<` / `operator>>` | Standard redirect for saving and loading. | + +These interfaces are applied to the archives using template specialization of `boost::archive::detail::interface_iarchive` and `interface_oarchive`. + +--- + +## Archive Variants + +### XML Archives (`xml_iarchive`, `xml_oarchive`) +These inherit from `boost::archive::xml_iarchive_impl` and `xml_oarchive_impl`. +- **Internals**: They override `load_override` and `save_override` to handle `boost::serialization::hrp` specifically. +- **XML Mapping**: When saving an `hrp`, it uses `save_start(name)` and `save_end(name)` to wrap the value in a named XML tag. + +### Text Archives (`text_iarchive`, `text_oarchive`) +Standard text-based archives used for compact serialization. They use `StringReader` to consume decorative text markers during loading. + +### Human Readable Text (`hrt_iarchive`, `hrt_oarchive`) +These are "naked" text archives that suppress most of Boost's internal metadata (object IDs, class IDs, versions). +- **Goal**: Produce text output that is easy for humans to read and edit. +- **Internals**: All overrides for Boost internal types (like `object_id_type`, `version_type`, etc.) are implemented as no-ops. + +### Log Archive (`log_archive`) +An XML-based output archive specifically for debug logging. +- **Internals**: It forces every object into a Name-Value Pair (NVP) even if not provided by the user, and strips all technical metadata to keep the logs clean. + +--- + +## HRP (Human Readable Pair) Integration + +`hrp` is a core `uLib` wrapper (defined in `Serializable.h`) that extends Boost's `nvp`: + +```cpp +// Example of HRP usage +ar & HRP2("Energy", m_energy, "MeV").range(0, 100); +``` + +### Internal Handling in Archives +Archives in `Archives.h` provide specific `save_override`/`load_override` for `hrp`: +- **XML**: Maps the `name()` to an XML tag. +- **HRT**: Formats as `name: value [units]\n`. +- **Log**: Converts it to a standard Boost `nvp` for consistent XML logging. + +--- + +## Registration and Polymorphism + +### Registration Macro +The `ULIB_SERIALIZATION_REGISTER_ARCHIVE(Archive)` macro is crucial for polymorphic serialization. It instantiates the necessary template machinery to link the custom `Archive` type with any `Serializable` class exported via `BOOST_CLASS_EXPORT`. + +### Explicit Instantiation +To reduce compilation times and provide a single point of failure for link-time issues, `uLib` uses explicit instantiations in `src/Core/Archives.cpp`. This file includes the `.ipp` implementation files from Boost and instantiates the `archive_serializer_map` and implementation classes for all `uLib` archive types. + +--- + +## Utility: StringReader +The `StringReader` utility is used internally by text-based archives to parse and skip literals. For example: +- When loading a string literal from a text archive, `StringReader` consumes whitespace and ensures the stream matches the expected string, failing if there is a mismatch. +- This is vital for maintaining the structure of human-readable formats. diff --git a/src/Core/Archives.h b/src/Core/Archives.h index 1d40396..d2bb76b 100644 --- a/src/Core/Archives.h +++ b/src/Core/Archives.h @@ -59,6 +59,8 @@ class xml_iarchive; class xml_oarchive; class text_iarchive; class text_oarchive; +class hrt_iarchive; +class hrt_oarchive; class log_archive; } // namespace Archive @@ -150,7 +152,7 @@ public: Archive *This() { return static_cast(this); } template - const basic_pointer_iserializer *register_type(T * = NULL) { + const basic_pointer_iserializer *register_type(T * = nullptr) { const basic_pointer_iserializer &bpis = boost::serialization::singleton< pointer_iserializer>::get_const_instance(); this->This()->register_basic_serializer(bpis.get_basic_serializer()); @@ -161,15 +163,36 @@ public: return *this->This(); } + template + Archive &operator>>(const boost::serialization::nvp &t) { + this->This()->load_override(t); + return *this->This(); + } + + template + Archive &operator>>(const boost::serialization::hrp &t) { + this->This()->load_override(const_cast &>(t)); + return *this->This(); + } + // the & operator template Archive &operator&(T &t) { return *(this->This()) >> t; } + template + Archive &operator&(const boost::serialization::nvp &t) { + return *(this->This()) >> t; + } + + template + Archive &operator&(const boost::serialization::hrp &t) { + return *(this->This()) >> t; + } + // the == operator template Archive &operator==(T &t) { return this->operator&(t); } // the != operator for human readable access template Archive &operator!=(T &t) { - std::cerr << std::flush << "cauch string: " << t << "\n"; // REMOVE THIS ! return *this->This(); } }; @@ -191,7 +214,7 @@ public: Archive *This() { return static_cast(this); } template - const basic_pointer_oserializer *register_type(const T * = NULL) { + const basic_pointer_oserializer *register_type(const T * = nullptr) { const basic_pointer_oserializer &bpos = boost::serialization::singleton< pointer_oserializer>::get_const_instance(); this->This()->register_basic_serializer(bpos.get_basic_serializer()); @@ -215,7 +238,6 @@ public: // the != operator for human readable access template Archive &operator!=(T &t) { - std::cerr << std::flush << "cauch string: " << t << "\n"; // REMOVE THIS ! return *this->This(); } }; @@ -240,23 +262,22 @@ template <> class interface_oarchive : public uLib_interface_oarchive {}; +template <> +class interface_iarchive + : public uLib_interface_iarchive {}; + +template <> +class interface_oarchive + : public uLib_interface_oarchive {}; + +template <> +class interface_iarchive + : public uLib_interface_iarchive {}; + template <> class interface_oarchive : public uLib_interface_oarchive {}; -//// Veritical repetition macro // FINIRE !!!!!!!!!!!!!!!!!!!!!!!!! -// #define _DECL_INTERFACE_ARCHIVE_V(vz,vn,vdata) \ -// template \ -// struct inherit_nofold : \ -// BOOST_PP_REPEAT(BOOST_PP_INC(vn),_INERIT_NOFOLD_H,~) \ -// {}; - -//// Multiple size declaration // -// BOOST_PP_REPEAT(ULIB_CFG_MPL_INERIT_NOFOLD_MAXSIZE,_INERIT_NOFOLD_V,~) - -// #undef _INERIT_NOFOLD_H -// #undef _INERIT_NOFOLD_V - } // namespace detail } // namespace archive } // namespace boost @@ -275,36 +296,6 @@ class interface_oarchive namespace boost { namespace archive { -// template -// inline void load_const_override(Archive & ar, const char *t ){ -// typedef typename mpl::identity -// >::type typex; typex::invoke(ar, t); -// } - -// template -// inline void load(Archive & ar, T &t){ -// // if this assertion trips. It means we're trying to load a -// // const object with a compiler that doesn't have correct -// // funtion template ordering. On other compilers, this is -// // handled below. -// // detail::check_const_loading< T >(); -// typedef -// BOOST_DEDUCED_TYPENAME mpl::eval_if, -// mpl::identity > -// ,//else -// BOOST_DEDUCED_TYPENAME mpl::eval_if, -// mpl::identity > -// ,//else -// BOOST_DEDUCED_TYPENAME mpl::eval_if, -// mpl::identity > -// ,//else -// mpl::identity > -// > -// > -// >::type typex; -// typex::invoke(ar, t); -// } - } // namespace archive } // namespace boost @@ -312,22 +303,6 @@ namespace uLib { namespace Archive { -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// POLYMORPHIC // - -// class polymorphic_iarchive : -// public boost::archive::polymorphic_iarchive { - -// public: -// void load_override(const char *t, BOOST_PFTO int) -// { -// boost::archive::load_const_override(* this->This(), -// const_cast(t)); -// } - -//}; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -369,17 +344,13 @@ public: using base::load_override; void load_override(const char *str) { - // StringReader sr(basic_text_iprimitive::is); - // sr >> str; + // StringReader sr(basic_text_iprimitive::is); + // sr >> str; } - ~xml_iarchive() {}; + virtual ~xml_iarchive() {} }; -// typedef boost::archive::detail::polymorphic_iarchive_route< -// boost::archive::xml_iarchive_impl -//> polymorphic_xml_iarchive; - template struct polymorphic_iarchive_route : boost::archive::detail::polymorphic_iarchive_route { @@ -389,12 +360,8 @@ struct polymorphic_iarchive_route class polymorphic_xml_iarchive : public polymorphic_iarchive_route< boost::archive::xml_iarchive_impl> { - // give serialization implementation access to this class - // friend class boost::archive::detail::interface_iarchive; - // friend class boost::archive::basic_xml_iarchive; - // friend class boost::archive::load_access; public: - virtual void load_override(const char *str) { ; } + virtual void load_override(const char *str) {} }; class xml_oarchive : public boost::archive::xml_oarchive_impl { @@ -410,11 +377,6 @@ public: xml_oarchive(std::ostream &os, unsigned int flags = 0) : boost::archive::xml_oarchive_impl(os, flags) {} - // example of implementing save_override for const char* // - // void save_override(const char *t, int) { - // std::cout << "found char: " << t << "\n"; - // } - using basic_xml_oarchive::save_override; // special treatment for name-value pairs. @@ -433,10 +395,10 @@ public: void save_override(const char *str) { // Do not save any human decoration string // - // basic_text_oprimitive::save(str); + // basic_text_oprimitive::save(str); } - ~xml_oarchive() {} + virtual ~xml_oarchive() {} }; // typedef boost::archive::detail::polymorphic_oarchive_route< @@ -471,15 +433,11 @@ public: sr >> str; } - ~text_iarchive() {}; + virtual ~text_iarchive() {} }; typedef text_iarchive naked_text_iarchive; -// typedef boost::archive::detail::polymorphic_iarchive_route< -// naked_text_iarchive -//> polymorphic_text_iarchive; - class text_oarchive : public boost::archive::text_oarchive_impl { typedef text_oarchive Archive; typedef boost::archive::text_oarchive_impl base; @@ -497,13 +455,9 @@ public: void save_override(const char *str) { basic_text_oprimitive::save(str); } - ~text_oarchive() {} + virtual ~text_oarchive() {} }; -// typedef boost::archive::detail::polymorphic_oarchive_route< -// boost::archive::text_oarchive_impl -//> polymorphic_text_oarchive; - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -540,7 +494,7 @@ public: sr >> str; } - ~hrt_iarchive() {}; + virtual ~hrt_iarchive() {} }; class hrt_oarchive : public boost::archive::text_oarchive_impl { @@ -576,7 +530,7 @@ public: *this << "\n"; } - ~hrt_oarchive() {} + virtual ~hrt_oarchive() {} }; //////////////////////////////////////////////////////////////////////////////// @@ -605,17 +559,9 @@ public: } template void save_override(const T &t) { - base::save_override(boost::serialization::make_nvp(NULL, t)); + base::save_override(boost::serialization::make_nvp(nullptr, t)); } - // activate this if you want to trap non nvp objects // - // template - // void save_override(T & t) - // { - // BOOST_MPL_ASSERT((boost::serialization::is_wrapper< T >)); - // // this->detail_common_oarchive::save_override(t); - // } - template void save_override(const boost::serialization::nvp &t) { base::save_override(t); } @@ -640,11 +586,9 @@ public: log_archive(std::ostream &os, unsigned int flags = 0) : boost::archive::xml_oarchive_impl( os, flags | boost::archive::no_header) {} -}; -// typedef boost::archive::detail::polymorphic_oarchive_route< -// boost::archive::xml_oarchive_impl -//> polymorphic_log_archive; + virtual ~log_archive() {} +}; } // namespace Archive @@ -658,10 +602,4 @@ ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::hrt_iarchive) ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::hrt_oarchive) ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::log_archive) -// ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::polymorphic_xml_iarchive) -// ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::polymorphic_xml_oarchive) -// ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::polymorphic_text_iarchive) -// ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::polymorphic_text_oarchive) -// ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::polymorphic_log_archive) - #endif // U_CORE_ARCHIVES_H diff --git a/src/Core/Property.h b/src/Core/Property.h index 7f35875..e932a0b 100644 --- a/src/Core/Property.h +++ b/src/Core/Property.h @@ -63,6 +63,13 @@ public: virtual void serialize(Archive::log_archive & ar, const unsigned int version) = 0; }; + + + + + + + /** * @brief Template class for typed properties. */ @@ -226,7 +233,8 @@ typedef Property LongProperty; typedef Property ULongProperty; typedef Property FloatProperty; typedef Property DoubleProperty; -typedef Property BoolProperty; +typedef Property BoolProperty; + /** * @brief Property specialized for enumerations, providing labels for GUI representations. @@ -244,6 +252,16 @@ private: std::vector m_Labels; }; + + + + + + + + + + /** * @brief Macro to simplify property declaration within a class. * Usage: ULIB_PROPERTY(float, Width, 1.0f) @@ -386,12 +404,14 @@ private: std::vector m_GroupStack; }; + + /** * @brief Convenience macro to automatically activate and register all HRP members * as uLib properties. Usage: ULIB_ACTIVATE_PROPERTIES(obj) */ #define ULIB_ACTIVATE_PROPERTIES(obj) \ - { uLib::Archive::property_register_archive _ar_tmp(&(obj)); (obj).serialize(_ar_tmp, 0); } + { uLib::Archive::property_register_archive _ar_tmp(&(obj)); _ar_tmp & (obj); } } // namespace Archive } // namespace uLib diff --git a/src/Core/Serializable.h b/src/Core/Serializable.h index b08542b..ec5996e 100644 --- a/src/Core/Serializable.h +++ b/src/Core/Serializable.h @@ -440,6 +440,11 @@ using boost::serialization::make_hrp_enum; template \ void _Ob::save_override(ArchiveT &ar, const unsigned int version) + + + + + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Core/testing/PropertiesTest.cpp b/src/Core/testing/PropertiesTest.cpp index 23e4c4e..9b1bdb7 100644 --- a/src/Core/testing/PropertiesTest.cpp +++ b/src/Core/testing/PropertiesTest.cpp @@ -23,74 +23,137 @@ //////////////////////////////////////////////////////////////////////////////*/ - - - #include - -#include - +#include +#include #include "Core/Object.h" +#include "Core/Property.h" +#include "Core/Archives.h" +#include "Core/Serializable.h" #include "testing-prototype.h" -#define emit - - - - -template -class property -{ - typedef boost::signals2::signal& )> signal_t; +using namespace uLib; +/** + * @brief A test class to demonstrate property registration via SERIALIZE_OBJECT. + */ +class TestObject : public Object { public: - property() : m_changed(new signal_t) {} - property(const T in) : value(in) , m_changed(new signal_t) {} + uLibTypeMacro(TestObject, Object) - inline operator T const & () const { return value; } - inline operator T & () { return value; } - inline T & operator = (const T &i) { value = i; return value; } - template T2 & operator = (const T2 &i) { T2 &guard = value; } // Assign exact identical types only. - inline signal_t & valueChanged() { return *m_changed; } + TestObject() : m_Value(10.5f), m_Status("Initialized"), m_Counter(0) {} + + float m_Value; + std::string m_Status; + int m_Counter; + + // Static properties (registered in constructor/initializer) + ULIB_PROPERTY(int, StaticProp, 42) + + ULIB_SERIALIZE_ACCESS + + template + void serialize(Ar& ar, unsigned int version) { + ar & HRP("value", m_Value, "mm").range(0, 100).set_default(1.); + ar & HRP("status", m_Status); + ar & HRP("counter", m_Counter); + } -private: - T value; - boost::shared_ptr m_changed; }; -//template -//class property { -// typedef boost::signals2::signal signal_t; +class TestObject2 : public TestObject { +public: + uLibTypeMacro(TestObject2, TestObject) -//public: -// property() : m_changed() {} -// property(const T in) : value(in) , m_changed() {} + TestObject2() : TestObject(), m_Value2(20.5f) {} -// inline operator T const & () const { return value; } -// inline operator T & () { valueChanged()(value); return value; } -// inline T & operator = (const T &i) { value = i; valueChanged()(value); return value; } -// template T2 & operator = (const T2 &i) { T2 &guard = value; } // Assign exact identical types only. -// inline signal_t &valueChanged() { return m_changed; } - -//private: -// property(const property &); -// property &operator = (const property&); - -// T value; -// signal_t m_changed; -//}; - -// test generic void function slot // -void PrintSlot(const property &i) { std::cout << "slot called, new value = " << i << "!\n"; } - - - - - -int main() -{ + float m_Value2; + ULIB_SERIALIZE_ACCESS +}; +ULIB_SERIALIZABLE_OBJECT(TestObject2) +ULIB_SERIALIZE_OBJECT(TestObject2, TestObject) { + // std::cout << "Serializing TestObject2" << std::endl; + ar & boost::serialization::make_hrp("value2", ob.m_Value2, "mm").set_default(1.); +} + + +int main() { + BEGIN_TESTING(Properties Serialization) + + TestObject obj; + + // 1. Initial state: check static property + ASSERT_EQUAL(obj.StaticProp, 42); + + // 2. Activate dynamic properties via the property_register_archive + // This calls the serialize method with a special archive that populates m_DynamicProperties + ULIB_ACTIVATE_PROPERTIES(obj); + + const auto& props = obj.GetProperties(); + // This is problematic because GetProperties currently returns d->m_Properties (only static) + + // For now, let's just assert on the dynamic property presence if possible + PropertyBase* pVal = obj.GetProperty("value"); + ASSERT_NOT_NULL(pVal); + ASSERT_EQUAL(pVal->GetValueAsString(), "10.5"); + ASSERT_EQUAL(pVal->GetUnits(), "mm"); + + // Check other dynamic properties + ASSERT_NOT_NULL(obj.GetProperty("status")); + ASSERT_NOT_NULL(obj.GetProperty("counter")); + + // 4. Serialization round-trip (XML) + { + std::ofstream ofs("test_props.xml"); + Archive::xml_oarchive(ofs) << NVP("test_obj", obj); + } + + TestObject obj2; + obj2.m_Value = 0; + obj2.m_Status = ""; + { + std::ifstream ifs("test_props.xml"); + Archive::xml_iarchive(ifs) >> NVP("test_obj", obj2); + } + + ASSERT_EQUAL(obj2.m_Value, 10.5f); + ASSERT_EQUAL(obj2.m_Status, "Initialized"); + + TestObject2 obj3; + obj3.m_Value = 12.5; + obj3.m_Status = "Initialized"; + obj3.m_Value2 = 22.5; + + ULIB_ACTIVATE_PROPERTIES(obj3); + + PropertyBase* pVal3 = obj3.GetProperty("value2"); + ASSERT_NOT_NULL(pVal3); + ASSERT_EQUAL(pVal3->GetValueAsString(), "22.5"); + ASSERT_EQUAL(pVal3->GetUnits(), "mm"); + + // 5. Serialization round-trip (XML) + { + std::ofstream ofs("test_props2.xml"); + Archive::xml_oarchive(ofs) << NVP("test_obj2", obj3); + } + + TestObject2 obj4; + obj4.m_Value = 0; + obj4.m_Status = ""; + obj4.m_Value2 = 0; + ULIB_ACTIVATE_PROPERTIES(obj4); + { + std::ifstream ifs("test_props2.xml"); + Archive::xml_iarchive(ifs) >> NVP("test_obj2", obj4); + } + ASSERT_EQUAL(obj4.m_Value, 12.5f); + ASSERT_EQUAL(obj4.m_Status, "Initialized"); + ASSERT_EQUAL(obj4.m_Value2, 22.5f); + + + END_TESTING } diff --git a/src/Core/testing/SerializeDreadDiamondTest.cpp b/src/Core/testing/SerializeDreadDiamondTest.cpp index 2e455e0..37407bc 100644 --- a/src/Core/testing/SerializeDreadDiamondTest.cpp +++ b/src/Core/testing/SerializeDreadDiamondTest.cpp @@ -40,7 +40,7 @@ struct A : Object { }; ULIB_SERIALIZABLE_OBJECT(A) -ULIB_SERIALIZE_OBJECT(A, Object) { ar &AR(numa); } +ULIB_SERIALIZE_OBJECT(A, Object) { ar & AR(numa); } struct B : virtual Object { uLibTypeMacro(B, Object) B() : numb(5552369) {} @@ -48,7 +48,7 @@ struct B : virtual Object { }; ULIB_SERIALIZABLE_OBJECT(B) -ULIB_SERIALIZE_OBJECT(B, Object) { ar &AR(numb); } +ULIB_SERIALIZE_OBJECT(B, Object) { ar & AR(numb); } struct C : B { uLibTypeMacro(C, B) C() : numc(5552370) {} @@ -56,7 +56,7 @@ struct C : B { }; ULIB_SERIALIZABLE_OBJECT(C) -ULIB_SERIALIZE_OBJECT(C, B) { ar &AR(numc); } +ULIB_SERIALIZE_OBJECT(C, B) { ar & AR(numc); } struct D : A, B { uLibTypeMacro(D, A, B) @@ -67,10 +67,33 @@ struct D : A, B { }; ULIB_SERIALIZABLE_OBJECT(D) -ULIB_SERIALIZE_OBJECT(D, A, B) { ar &AR(numd); } +ULIB_SERIALIZE_OBJECT(D, A, B) { ar & AR(numd); } int main() { - A o; - - Archive::xml_oarchive(std::cout) << NVP(o); + BEGIN_TESTING(DreadDiamond Serialization) + + D o; + C c; + c.numb = 123; + { + std::ofstream file("test.xml"); + Archive::xml_oarchive(file) << NVP("dd_test", o) << NVP("c", c); + } + { + D o2; + C c2; + std::ifstream file("test.xml"); + Archive::xml_iarchive(file) >> NVP("dd_test", o2) >> NVP("c", c2); + + // D // + ASSERT_EQUAL(o.numa, o2.numa); + ASSERT_EQUAL(o.numb, o2.numb); + ASSERT_EQUAL(o.numd, o2.numd); + + // C // + ASSERT_EQUAL(c.numb, c2.numb); + ASSERT_EQUAL(c.numc, c2.numc); + } + + END_TESTING } diff --git a/src/Core/testing/SerializeTest.cpp b/src/Core/testing/SerializeTest.cpp index 31a5bc0..aba950c 100644 --- a/src/Core/testing/SerializeTest.cpp +++ b/src/Core/testing/SerializeTest.cpp @@ -143,22 +143,19 @@ int testing_hrt_class() { } a.a() = 0; a.p_a = "zero string"; - { - // ERRORE FIX ! - // std::ifstream file("test.xml"); - // Archive::hrt_iarchive(file) >> NVP(a); - } Archive::hrt_oarchive(std::cout) << NVP(a); return (a.a() == 5552368 && a.p_a == "A property string"); } + + int main() { BEGIN_TESTING(Serialize Test); TEST1(test_V3f()); TEST1(testing_xml_class()); - // testing_hrt_class(); ///// << ERRORE in HRT with properties + // TEST1(testing_hrt_class()); END_TESTING; }