1 /*
2   Copyright (c) 2014, Randolph Voorhies, Shane Grant
3   All rights reserved.
4 
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7       * Redistributions of source code must retain the above copyright
8         notice, this list of conditions and the following disclaimer.
9       * Redistributions in binary form must reproduce the above copyright
10         notice, this list of conditions and the following disclaimer in the
11         documentation and/or other materials provided with the distribution.
12       * Neither the name of cereal nor the
13         names of its contributors may be used to endorse or promote products
14         derived from this software without specific prior written permission.
15 
16   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
20   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #ifndef CEREAL_TEST_VERSIONING_H_
28 #define CEREAL_TEST_VERSIONING_H_
29 #include "common.hpp"
30 
31 #if CEREAL_THREAD_SAFE
32 #include <future>
33 #endif
34 
35 namespace Nested
36 {
37   struct NestedClass
38   {
39     int x;
40 
41     template <class Archive>
serializeNested::NestedClass42     void serialize( Archive & ar )
43     { ar( x ); }
44   };
45 }
46 
47 CEREAL_CLASS_VERSION( Nested::NestedClass, 1 )
48 
49 class VersionStructMS
50 {
51   public:
52     bool x;
53     std::uint32_t v;
54 
55   private:
56     friend class cereal::access;
57     template <class Archive>
serialize(Archive & ar,std::uint32_t const version)58     void serialize( Archive & ar, std::uint32_t const version )
59     {
60       ar( x );
61       v = version;
62     }
63 };
64 
65 struct VersionStructMSP
66 {
67   uint8_t x;
68   std::uint32_t v;
69   template <class Archive>
saveVersionStructMSP70   void save( Archive & ar, std::uint32_t const /*version*/ ) const
71   {
72     ar( x );
73   }
74 
75   template <class Archive>
loadVersionStructMSP76   void load( Archive & ar, std::uint32_t const version )
77   {
78     ar( x );
79     v = version;
80   }
81 };
82 
83 struct VersionStructNMS
84 {
85   std::int32_t x;
86   std::uint32_t v;
87 };
88 
89 template <class Archive>
serialize(Archive & ar,VersionStructNMS & vnms,const std::uint32_t version)90 void serialize( Archive & ar, VersionStructNMS & vnms, const std::uint32_t version )
91 {
92   ar( vnms.x );
93   vnms.v = version;
94 }
95 
96 struct VersionStructNMSP
97 {
98   double x;
99   std::uint32_t v;
100 };
101 
102 template <class Archive>
save(Archive & ar,VersionStructNMSP const & vnms,const std::uint32_t)103 void save( Archive & ar, VersionStructNMSP const & vnms, const std::uint32_t /*version*/ )
104 {
105   ar( vnms.x );
106 }
107 
108 template <class Archive>
load(Archive & ar,VersionStructNMSP & vnms,const std::uint32_t version)109 void load( Archive & ar, VersionStructNMSP & vnms, const std::uint32_t version )
110 {
111   ar( vnms.x );
112   vnms.v = version;
113 }
114 
115 CEREAL_CLASS_VERSION( VersionStructMSP, 33 )
116 CEREAL_CLASS_VERSION( VersionStructNMS, 66 )
117 CEREAL_CLASS_VERSION( VersionStructNMSP, 99 )
118 
119 template <class IArchive, class OArchive> inline
test_versioning()120 void test_versioning()
121 {
122   std::random_device rd;
123   std::mt19937 gen(rd());
124 
125   #if CEREAL_THREAD_SAFE
126   #include <future>
127   static std::mutex testMutex;
128   #endif
129 
130   for(size_t i=0; i<100; ++i)
131   {
132     VersionStructMS o_MS      = {random_value<uint8_t>(gen) % 2 ? true : false, 1};
133     VersionStructMSP o_MSP    = {random_value<uint8_t>(gen), 1};
134     VersionStructNMS o_NMS    = {random_value<int32_t>(gen), 1};
135     VersionStructNMSP o_NMSP  = {random_value<double>(gen), 1};
136     VersionStructMS o_MS2     = {random_value<uint8_t>(gen) % 2 ? true : false, 1};
137     VersionStructMSP o_MSP2   = {random_value<uint8_t>(gen), 1};
138     VersionStructNMS o_NMS2   = {random_value<int32_t>(gen), 1};
139     VersionStructNMSP o_NMSP2 = {random_value<double>(gen), 1};
140 
141     std::ostringstream os;
142     {
143       OArchive oar(os);
144       oar( o_MS );
145       oar( o_MSP );
146       oar( o_NMS );
147       oar( o_NMSP );
148       oar( o_MS2 );
149       oar( o_MSP2 );
150       oar( o_NMS2 );
151       oar( o_NMSP2 );
152     }
153 
154     decltype(o_MS) i_MS;
155     decltype(o_MSP) i_MSP;
156     decltype(o_NMS) i_NMS;
157     decltype(o_NMSP) i_NMSP;
158     decltype(o_MS2) i_MS2;
159     decltype(o_MSP2) i_MSP2;
160     decltype(o_NMS2) i_NMS2;
161     decltype(o_NMSP2) i_NMSP2;
162 
163     std::istringstream is(os.str());
164     {
165       IArchive iar(is);
166       iar( i_MS );
167       iar( i_MSP );
168       iar( i_NMS );
169       iar( i_NMSP );
170       iar( i_MS2 );
171       iar( i_MSP2 );
172       iar( i_NMS2 );
173       iar( i_NMSP2 );
174     }
175 
176     #if CEREAL_THREAD_SAFE
177     std::lock_guard<std::mutex> lock( testMutex );
178     #endif
179 
180     CHECK_EQ(o_MS.x, i_MS.x);
181     CHECK_EQ(i_MS.v, 0u);
182     CHECK_EQ(o_MSP.x, i_MSP.x);
183     CHECK_EQ(i_MSP.v, 33u);
184     CHECK_EQ(o_NMS.x, i_NMS.x);
185     CHECK_EQ(i_NMS.v, 66u);
186     CHECK_EQ(o_NMSP.x, doctest::Approx(i_NMSP.x).epsilon(1e-5));
187     CHECK_EQ(i_NMSP.v, 99u);
188 
189     CHECK_EQ(o_MS2.x, i_MS2.x);
190     CHECK_EQ(i_MS2.v, 0u);
191     CHECK_EQ(o_MSP2.x, i_MSP2.x);
192     CHECK_EQ(i_MSP2.v, 33u);
193     CHECK_EQ(o_NMS2.x, i_NMS2.x);
194     CHECK_EQ(i_NMS2.v, 66u);
195     CHECK_EQ(o_NMSP2.x, doctest::Approx(i_NMSP2.x).epsilon(1e-5));
196     CHECK_EQ(i_NMSP2.v, 99u);
197     }
198 }
199 
200 #if CEREAL_THREAD_SAFE
201 template <class IArchive, class OArchive> inline
test_versioning_threading()202 void test_versioning_threading()
203 {
204   std::vector<std::future<bool>> pool;
205   for( size_t i = 0; i < 100; ++i )
206     pool.emplace_back( std::async( std::launch::async,
207                                    [](){ test_versioning<IArchive, OArchive>(); return true; } ) );
208 
209   for( auto & future : pool )
210     future.wait();
211 
212   for( auto & future : pool )
213     CHECK_UNARY( future.get() );
214 }
215 #endif // CEREAL_THREAD_SAFE
216 
217 #endif // CEREAL_TEST_VERSIONING_H_
218