@@ -15,22 +15,31 @@ struct TestDataV2 {
1515 description : String ,
1616}
1717
18+ #[ derive( Debug , Clone , PartialEq , Serialize , Deserialize ) ]
19+ struct TestDataV3 {
20+ id : u32 ,
21+ name : String ,
22+ description : String ,
23+ tags : Vec < String > ,
24+ }
25+
1826#[ derive( Clone ) ]
1927enum TestData {
2028 V1 ( TestDataV1 ) ,
2129 V2 ( TestDataV2 ) ,
30+ V3 ( TestDataV3 ) ,
2231}
2332
2433impl OwnedVersionedData for TestData {
25- type Latest = TestDataV2 ;
34+ type Latest = TestDataV3 ;
2635
27- fn wrap_latest ( latest : TestDataV2 ) -> Self {
28- TestData :: V2 ( latest)
36+ fn wrap_latest ( latest : TestDataV3 ) -> Self {
37+ TestData :: V3 ( latest)
2938 }
3039
3140 fn unwrap_latest ( self ) -> Result < Self :: Latest > {
3241 #[ allow( irrefutable_let_patterns) ]
33- if let TestData :: V2 ( data) = self {
42+ if let TestData :: V3 ( data) = self {
3443 Ok ( data)
3544 } else {
3645 bail ! ( "version not latest" ) ;
@@ -41,6 +50,7 @@ impl OwnedVersionedData for TestData {
4150 match version {
4251 1 => Ok ( TestData :: V1 ( serde_bare:: from_slice ( payload) ?) ) ,
4352 2 => Ok ( TestData :: V2 ( serde_bare:: from_slice ( payload) ?) ) ,
53+ 3 => Ok ( TestData :: V3 ( serde_bare:: from_slice ( payload) ?) ) ,
4454 _ => bail ! ( "invalid version: {version}" ) ,
4555 }
4656 }
@@ -49,15 +59,16 @@ impl OwnedVersionedData for TestData {
4959 match self {
5060 TestData :: V1 ( data) => serde_bare:: to_vec ( & data) . map_err ( Into :: into) ,
5161 TestData :: V2 ( data) => serde_bare:: to_vec ( & data) . map_err ( Into :: into) ,
62+ TestData :: V3 ( data) => serde_bare:: to_vec ( & data) . map_err ( Into :: into) ,
5263 }
5364 }
5465
5566 fn deserialize_converters ( ) -> Vec < impl Fn ( Self ) -> Result < Self > > {
56- vec ! [ Self :: v1_to_v2]
67+ vec ! [ Self :: v1_to_v2, Self :: v2_to_v3 ]
5768 }
5869
5970 fn serialize_converters ( ) -> Vec < impl Fn ( Self ) -> Result < Self > > {
60- vec ! [ Self :: v2_to_v1]
71+ vec ! [ Self :: v3_to_v2 , Self :: v2_to_v1]
6172 }
6273}
6374
@@ -110,7 +121,30 @@ impl TestData {
110121 name : v1. name ,
111122 description : "default" . to_string ( ) ,
112123 } ) ) ,
113- v2 => Ok ( v2) ,
124+ other => Ok ( other) ,
125+ }
126+ }
127+
128+ fn v2_to_v3 ( self ) -> Result < Self > {
129+ match self {
130+ TestData :: V2 ( v2) => Ok ( TestData :: V3 ( TestDataV3 {
131+ id : v2. id ,
132+ name : v2. name ,
133+ description : v2. description ,
134+ tags : vec ! [ ] ,
135+ } ) ) ,
136+ other => Ok ( other) ,
137+ }
138+ }
139+
140+ fn v3_to_v2 ( self ) -> Result < Self > {
141+ match self {
142+ TestData :: V3 ( v3) => Ok ( TestData :: V2 ( TestDataV2 {
143+ id : v3. id ,
144+ name : v3. name ,
145+ description : v3. description ,
146+ } ) ) ,
147+ other => Ok ( other) ,
114148 }
115149 }
116150
@@ -120,7 +154,7 @@ impl TestData {
120154 id : v2. id ,
121155 name : v2. name ,
122156 } ) ) ,
123- v1 => Ok ( v1 ) ,
157+ other => Ok ( other ) ,
124158 }
125159 }
126160}
@@ -151,37 +185,112 @@ fn test_v2_to_v2() {
151185
152186 let payload = TestData :: V2 ( data. clone ( ) ) . serialize ( 2 ) . unwrap ( ) ;
153187
188+ // V2 data deserialized with version 2 will be converted to V3 (latest)
154189 let deserialized = TestData :: deserialize ( & payload, 2 ) . unwrap ( ) ;
155190 assert_eq ! ( deserialized. id, 456 ) ;
156191 assert_eq ! ( deserialized. name, "test" ) ;
157192 assert_eq ! ( deserialized. description, "data" ) ;
193+ assert_eq ! ( deserialized. tags. len( ) , 0 ) ; // Tags default to empty vec
158194}
159195
160196#[ test]
161197fn test_unsupported_version ( ) {
162198 assert ! ( TestData :: deserialize( & [ ] , 99 ) . is_err( ) ) ;
163199}
164200
201+ #[ test]
202+ fn test_v3_to_v2 ( ) {
203+ // This is the critical test case: serializing from V3 to V2
204+ // With 3 versions and 2 serialize converters (V3->V2, V2->V1),
205+ // serializing to version 2 should apply 1 converter (V3->V2)
206+ let data = TestDataV3 {
207+ id : 789 ,
208+ name : "v3_test" . to_string ( ) ,
209+ description : "test description" . to_string ( ) ,
210+ tags : vec ! [ "tag1" . to_string( ) , "tag2" . to_string( ) ] ,
211+ } ;
212+
213+ // Serialize V3 data to V2 format (should strip tags)
214+ let payload = TestData :: V3 ( data. clone ( ) ) . serialize ( 2 ) . unwrap ( ) ;
215+
216+ // Deserialize as V2 and verify tags were stripped
217+ let deserialized = TestData :: deserialize ( & payload, 2 ) . unwrap ( ) ;
218+ assert_eq ! ( deserialized. id, 789 ) ;
219+ assert_eq ! ( deserialized. name, "v3_test" ) ;
220+ assert_eq ! ( deserialized. description, "test description" ) ;
221+ // Tags should not be present in V2
222+ }
223+
224+ #[ test]
225+ fn test_v3_to_v1 ( ) {
226+ // Test serializing from V3 all the way down to V1
227+ // Should apply both converters: V3->V2, then V2->V1
228+ let data = TestDataV3 {
229+ id : 999 ,
230+ name : "v3_to_v1_test" . to_string ( ) ,
231+ description : "should be stripped" . to_string ( ) ,
232+ tags : vec ! [ "will be removed" . to_string( ) ] ,
233+ } ;
234+
235+ // Serialize V3 data to V1 format
236+ let payload = TestData :: V3 ( data. clone ( ) ) . serialize ( 1 ) . unwrap ( ) ;
237+
238+ // Deserialize as V1 and verify both description and tags were stripped
239+ let deserialized = TestData :: deserialize ( & payload, 1 ) . unwrap ( ) ;
240+ assert_eq ! ( deserialized. id, 999 ) ;
241+ assert_eq ! ( deserialized. name, "v3_to_v1_test" ) ;
242+ assert_eq ! ( deserialized. description, "default" ) ;
243+ assert_eq ! ( deserialized. tags. len( ) , 0 ) ;
244+ }
245+
246+ #[ test]
247+ fn test_v3_to_v3 ( ) {
248+ // Test that serializing V3 to V3 preserves all data
249+ let data = TestDataV3 {
250+ id : 123 ,
251+ name : "v3_same" . to_string ( ) ,
252+ description : "preserved" . to_string ( ) ,
253+ tags : vec ! [ "keep" . to_string( ) ] ,
254+ } ;
255+
256+ let payload = TestData :: V3 ( data. clone ( ) ) . serialize ( 3 ) . unwrap ( ) ;
257+
258+ let deserialized = TestData :: deserialize ( & payload, 3 ) . unwrap ( ) ;
259+ assert_eq ! ( deserialized. id, 123 ) ;
260+ assert_eq ! ( deserialized. name, "v3_same" ) ;
261+ assert_eq ! ( deserialized. description, "preserved" ) ;
262+ assert_eq ! ( deserialized. tags, vec![ "keep" . to_string( ) ] ) ;
263+ }
264+
165265#[ test]
166266fn test_serialize ( ) {
167- let data = TestData :: V2 ( TestDataV2 {
267+ let data = TestData :: V3 ( TestDataV3 {
168268 id : 456 ,
169269 name : "serialize_test" . to_string ( ) ,
170270 description : "will be stripped" . to_string ( ) ,
271+ tags : vec ! [ "tag1" . to_string( ) ] ,
171272 } ) ;
172273
173- // Test serializing to V1 (should convert V2 -> V1)
274+ // Test serializing to V1 (should convert V3 -> V2 -> V1)
174275 let result = data. clone ( ) . serialize ( 1 ) . unwrap ( ) ;
175276 let deserialized: TestDataV1 = serde_bare:: from_slice ( & result) . unwrap ( ) ;
176277 assert_eq ! ( deserialized. id, 456 ) ;
177278 assert_eq ! ( deserialized. name, "serialize_test" ) ;
178279
179- // Test serializing to V2
180- let result = data. serialize ( 2 ) . unwrap ( ) ;
280+ // Test serializing to V2 (should convert V3 -> V2)
281+ let result = data. clone ( ) . serialize ( 2 ) . unwrap ( ) ;
181282 let deserialized: TestDataV2 = serde_bare:: from_slice ( & result) . unwrap ( ) ;
182283 assert_eq ! ( deserialized. id, 456 ) ;
183284 assert_eq ! ( deserialized. name, "serialize_test" ) ;
184285 assert_eq ! ( deserialized. description, "will be stripped" ) ;
286+
287+ // Test serializing to V3 (no conversion)
288+ let result = data. serialize ( 3 ) . unwrap ( ) ;
289+ let deserialized: TestDataV3 = serde_bare:: from_slice ( & result) . unwrap ( ) ;
290+ assert_eq ! ( deserialized. id, 456 ) ;
291+ assert_eq ! ( deserialized. name, "serialize_test" ) ;
292+ assert_eq ! ( deserialized. description, "will be stripped" ) ;
293+ assert_eq ! ( deserialized. tags, vec![ "tag1" . to_string( ) ] ) ;
185294}
186295
187296#[ test]
@@ -196,14 +305,16 @@ fn test_embedded_v2_to_v1_to_v2() {
196305 . serialize_with_embedded_version ( 1 )
197306 . unwrap ( ) ;
198307
199- // First 2 bytes should be the version (2 in little-endian)
308+ // First 2 bytes should be the version (1 in little-endian)
200309 assert_eq ! ( payload[ 0 ] , 1u8 ) ;
201310 assert_eq ! ( payload[ 1 ] , 0u8 ) ;
202311
312+ // Deserializing V1 data converts it to V3 (latest)
203313 let deserialized = TestData :: deserialize_with_embedded_version ( & payload) . unwrap ( ) ;
204314 assert_eq ! ( deserialized. id, 456 ) ;
205315 assert_eq ! ( deserialized. name, "test" ) ;
206316 assert_eq ! ( deserialized. description, "default" ) ;
317+ assert_eq ! ( deserialized. tags. len( ) , 0 ) ;
207318}
208319
209320#[ test]
@@ -222,10 +333,12 @@ fn test_embedded_v2_to_v2() {
222333 assert_eq ! ( payload[ 0 ] , 2u8 ) ;
223334 assert_eq ! ( payload[ 1 ] , 0u8 ) ;
224335
336+ // Deserializing V2 data converts it to V3 (latest)
225337 let deserialized = TestData :: deserialize_with_embedded_version ( & payload) . unwrap ( ) ;
226338 assert_eq ! ( deserialized. id, 456 ) ;
227339 assert_eq ! ( deserialized. name, "test" ) ;
228340 assert_eq ! ( deserialized. description, "data" ) ;
341+ assert_eq ! ( deserialized. tags. len( ) , 0 ) ;
229342}
230343
231344#[ test]
0 commit comments