@@ -30,6 +30,7 @@ internal static class SerializationTestData {
3030 private static DateTimeOffset dateTimeOffset = new DateTimeOffset ( 1990 , 1 , 2 , 3 , 4 , 5 , TimeSpan . FromHours ( 1 ) ) ;
3131
3232 public static IEnumerable < object [ ] > TestData ( FirebaseFirestore database ) {
33+ // TODO(b/153551034): Refactor this using structs or classes.
3334 return new List < object [ ] >
3435 {
3536 // Simple types
@@ -91,10 +92,8 @@ public static IEnumerable<object[]> TestData(FirebaseFirestore database) {
9192 // We don't cover the whole range of ulong
9293 { new object [ ] { UInt64Enum . MinValue , ( long ) 0 } } ,
9394 { new object [ ] { UInt64Enum . MaxRepresentableValue , ( long ) long . MaxValue } } ,
94- #if ! UNITY_IOS // TODO(b/141830498): Fix iOS issues.
9595 { new object [ ] { CustomConversionEnum . Foo , "Foo" } } ,
9696 { new object [ ] { CustomConversionEnum . Bar , "Bar" } } ,
97- #endif
9897
9998 // Timestamps
10099 { new object [ ] { Timestamp . FromDateTime ( dateTime ) ,
@@ -116,36 +115,43 @@ public static IEnumerable<object[]> TestData(FirebaseFirestore database) {
116115 // Array values
117116 { new object [ ] { new string [ ] { "x" , "y" } , new List < object > { "x" , "y" } } } ,
118117 { new object [ ] { new List < string > { "x" , "y" } , new List < object > { "x" , "y" } } } ,
118+ { new object [ ] { new int [ ] { 3 , 4 } , new List < object > { 3L , 4L } } } ,
119119 // Deliberately DateTime rather than Timestamp here - we need to be able to detect the element type to perform the
120120 // per-element deserialization correctly
121121 { new object [ ] { new List < DateTime > { dateTime , dateTime } ,
122122 new List < object > { Timestamp . FromDateTime ( dateTime ) , Timestamp . FromDateTime ( dateTime ) } } } ,
123123
124- // Map values (that can be deserialized again): dictionaries, attributed types, expandos (which are just dictionaries), custom serialized map-like values
124+ // Map values (that can be deserialized again): dictionaries, attributed types, expandos (which are
125+ // just dictionaries), custom serialized map-like values
125126
126127 // Dictionaries
127- { new object [ ] { new Dictionary < string , object > { { "name" , "Jon" } , { "score" , 10L } } ,
128- new Dictionary < string , object > { { "name" , "Jon" } , { "score" , 10L } } } } ,
129- #if ! UNITY_IOS // TODO(b/141830498): Fix iOS issues.
128+ { new object [ ] { new Dictionary < string , byte > { { "A" , 10 } , { "B" , 20 } } ,
129+ new Dictionary < string , object > { { "A" , 10L } , { "B" , 20L } } } } ,
130130 { new object [ ] { new Dictionary < string , int > { { "A" , 10 } , { "B" , 20 } } ,
131131 new Dictionary < string , object > { { "A" , 10L } , { "B" , 20L } } } } ,
132- #endif
132+ { new object [ ] { new Dictionary < string , object > { { "name" , "Jon" } , { "score" , 10L } } ,
133+ new Dictionary < string , object > { { "name" , "Jon" } , { "score" , 10L } } } } ,
133134 // Attributed type (each property has an attribute)
134135 { new object [ ] { new GameResult { Name = "Jon" , Score = 10 } ,
135136 new Dictionary < string , object > { { "name" , "Jon" } , { "Score" , 10L } } } } ,
137+ // Attributed type contained in a dictionary
138+ { new object [ ] {
139+ new Dictionary < string , GameResult >
140+ { { "result" , new GameResult { Name = "Jon" , Score = 10 } } } ,
141+ new Dictionary < string , object >
142+ { { "result" ,
143+ new Dictionary < string , object >
144+ { { "name" , "Jon" } , { "Score" , 10L } } } } } } ,
136145 // Attributed type containing a dictionary
137- #if ! UNITY_IOS // TODO(b/141830498): Fix iOS issues.
138146 { new object [ ] { new DictionaryInterfaceContainer { Integers = new Dictionary < string , int > { { "A" , 10 } , { "B" , 20 } } } ,
139147 new Dictionary < string , object > {
140148 { "Integers" , new Dictionary < string , object > { { "A" , 10L } , { "B" , 20L } } }
141149 } } } ,
142150 // Attributed type serialized and deserialized by CustomPlayerConverter
143151 { new object [ ] { new CustomPlayer { Name = "Amanda" , Score = 15 } ,
144152 new Dictionary < string , object > { { "PlayerName" , "Amanda" } , { "PlayerScore" , 15L } } } } ,
145- #endif
146153
147154 // Attributed value type serialized and deserialized by CustomValueTypeConverter
148- #if ! UNITY_IOS // TODO(b/141830498): Fix iOS issues.
149155 { new object [ ] { new CustomValueType ( "xyz" , 10 ) ,
150156 new Dictionary < string , object > { { "Name" , "xyz" } , { "Value" , 10L } } } } ,
151157
@@ -156,29 +162,35 @@ public static IEnumerable<object[]> TestData(FirebaseFirestore database) {
156162 { "EnumAttributedByName" , "MinValue" } ,
157163 { "EnumByNumber" , ( long ) int . MaxValue }
158164 } } } ,
159- #endif
160165
161166 // Attributed struct
162167 { new object [ ] { new StructModel { Name = "xyz" , Value = 10 } ,
163168 new Dictionary < string , object > { { "Name" , "xyz" } , { "Value" , 10L } } } } ,
164169
165- // Nullable type handling
166- #if ! UNITY_IOS // TODO(b/141830498): Fix iOS issues.
167- { new object [ ] { new NullableContainer { NullableValue = null } ,
168- new Dictionary < string , object > { { "NullableValue" , null } } } } ,
169- { new object [ ] { new NullableContainer { NullableValue = 10 } ,
170- new Dictionary < string , object > { { "NullableValue" , 10L } } } } ,
171- { new object [ ] { new NullableEnumContainer { NullableValue = null } ,
172- new Dictionary < string , object > { { "NullableValue" , null } } } } ,
173- { new object [ ] { new NullableEnumContainer { NullableValue = ( Int32Enum ) 10 } ,
174- new Dictionary < string , object > { { "NullableValue" , 10L } } } } ,
175- #endif
176-
177170 // Document references
178171 { new object [ ] { database . Document ( "a/b" ) , database . Document ( "a/b" ) } } ,
179172 } ;
180173 }
181174
175+
176+ public static IEnumerable < object [ ] > UnsupportedTestData ( ) {
177+ return new List < object [ ] >
178+ {
179+ // Nullable type handling
180+ { new object [ ] { new NullableContainer { NullableValue = 10 } ,
181+ new Dictionary < string , object > { { "NullableValue" , 10L } } } } ,
182+ { new object [ ] { new NullableEnumContainer { NullableValue = ( Int32Enum ) 10 } ,
183+ new Dictionary < string , object > { { "NullableValue" , 10L } } } } ,
184+ // This one fails because the `NullableContainer` it gets back has a random value
185+ // while it should be null.
186+ { new object [ ] { new NullableContainer { NullableValue = null } ,
187+ new Dictionary < string , object > { { "NullableValue" , null } } } } ,
188+ { new object [ ] { new NullableEnumContainer { NullableValue = null } ,
189+ new Dictionary < string , object > { { "NullableValue" , null } } } } ,
190+ } ;
191+
192+ }
193+
182194 // Only equatable for the sake of testing; that's not a requirement of the serialization code.
183195 [ FirestoreData ]
184196 internal class GameResult : IEquatable < GameResult > {
@@ -197,21 +209,22 @@ internal class GameResult : IEquatable<GameResult> {
197209 [ FirestoreData ]
198210 internal class NullableContainer : IEquatable < NullableContainer > {
199211 [ FirestoreProperty ]
200- public int ? NullableValue { get ; set ; }
212+ public long ? NullableValue { get ; set ; }
201213
202- public override int GetHashCode ( ) { return NullableValue . GetValueOrDefault ( ) ; }
214+ public override int GetHashCode ( ) { return ( int ) NullableValue . GetValueOrDefault ( ) . GetHashCode ( ) ; }
203215
204216 public override bool Equals ( object obj ) { return Equals ( obj as NullableContainer ) ; }
205217
206218 public bool Equals ( NullableContainer other ) { return other != null && other . NullableValue == NullableValue ; }
219+ public override string ToString ( ) { return String . Format ( "NullableContainer: {0}" , NullableValue . GetValueOrDefault ( ) ) ; }
207220 }
208221
209222 [ FirestoreData ]
210223 internal class NullableEnumContainer : IEquatable < NullableEnumContainer > {
211224 [ FirestoreProperty ]
212225 public Int32Enum ? NullableValue { get ; set ; }
213226
214- public override int GetHashCode ( ) { return ( int ) NullableValue . GetValueOrDefault ( ) ; }
227+ public override int GetHashCode ( ) { return ( int ) NullableValue . GetValueOrDefault ( ) . GetHashCode ( ) ; }
215228
216229 public override bool Equals ( object obj ) { return Equals ( obj as NullableEnumContainer ) ; }
217230
@@ -331,8 +344,8 @@ public sealed class Email {
331344 public Email ( string address ) { Address = address ; }
332345 }
333346
334- public class EmailConverter : IFirestoreConverter < Email > {
335- public Email FromFirestore ( object value ) {
347+ public class EmailConverter : FirestoreConverter < Email > {
348+ public override Email FromFirestore ( object value ) {
336349 if ( value == null ) {
337350 throw new ArgumentNullException ( "value" ) ; // Shouldn't happen
338351 } else if ( value is string ) {
@@ -341,7 +354,7 @@ public Email FromFirestore(object value) {
341354 throw new ArgumentException ( String . Format ( "Unexpected data: {}" , value . GetType ( ) ) ) ;
342355 }
343356 }
344- public object ToFirestore ( Email value ) { return value == null ? null : value . Address ; }
357+ public override object ToFirestore ( Email value ) { return value == null ? null : value . Address ; }
345358 }
346359
347360 [ FirestoreData ]
@@ -370,8 +383,8 @@ public class GuidPair2 {
370383 public Guid ? GuidOrNull { get ; set ; }
371384 }
372385
373- public class GuidConverter : IFirestoreConverter < Guid > {
374- public Guid FromFirestore ( object value ) {
386+ public class GuidConverter : FirestoreConverter < Guid > {
387+ public override Guid FromFirestore ( object value ) {
375388 if ( value == null ) {
376389 throw new ArgumentNullException ( "value" ) ; // Shouldn't happen
377390 } else if ( value is string ) {
@@ -380,7 +393,7 @@ public Guid FromFirestore(object value) {
380393 throw new ArgumentException ( String . Format ( "Unexpected data: {0}" , value . GetType ( ) ) ) ;
381394 }
382395 }
383- public object ToFirestore ( Guid value ) { return value . ToString ( "N" ) ; }
396+ public override object ToFirestore ( Guid value ) { return value . ToString ( "N" ) ; }
384397 }
385398
386399 // Only equatable for the sake of testing; that's not a requirement of the serialization code.
@@ -394,17 +407,17 @@ public class CustomPlayer : IEquatable<CustomPlayer> {
394407 public bool Equals ( CustomPlayer other ) { return other != null && other . Name == Name && other . Score == Score ; }
395408 }
396409
397- public class CustomPlayerConverter : IFirestoreConverter < CustomPlayer > {
398- public CustomPlayer FromFirestore ( object value ) {
399- var map = ( IDictionary < string , object > ) value ;
410+ public class CustomPlayerConverter : FirestoreConverter < CustomPlayer > {
411+ public override CustomPlayer FromFirestore ( object value ) {
412+ var map = ( IDictionary < string , object > ) value ;
400413 return new CustomPlayer {
401- Name = ( string ) map [ "PlayerName" ] ,
414+ Name = ( string ) map [ "PlayerName" ] ,
402415 // Unbox to long, then convert to int.
403- Score = ( int ) ( long ) map [ "PlayerScore" ]
416+ Score = ( int ) ( long ) map [ "PlayerScore" ]
404417 } ;
405418 }
406419
407- public object ToFirestore ( CustomPlayer value ) {
420+ public override object ToFirestore ( CustomPlayer value ) {
408421 return new Dictionary < string , object >
409422 {
410423 { "PlayerName" , value . Name } ,
@@ -424,21 +437,21 @@ public CustomValueType(string name, int value) {
424437 }
425438
426439 public override int GetHashCode ( ) { return Name . GetHashCode ( ) + Value ; }
427- public override bool Equals ( object obj ) { return obj is CustomValueType && Equals ( ( CustomValueType ) obj ) ; }
440+ public override bool Equals ( object obj ) { return obj is CustomValueType && Equals ( ( CustomValueType ) obj ) ; }
428441 public bool Equals ( CustomValueType other ) { return Name == other . Name && Value == other . Value ; }
429442 public override string ToString ( ) { return String . Format ( "CustomValueType: {0}" , new { Name , Value } ) ; }
430443 }
431444
432- internal class CustomValueTypeConverter : IFirestoreConverter < CustomValueType > {
433- public CustomValueType FromFirestore ( object value ) {
434- var dictionary = ( IDictionary < string , object > ) value ;
445+ internal class CustomValueTypeConverter : FirestoreConverter < CustomValueType > {
446+ public override CustomValueType FromFirestore ( object value ) {
447+ var dictionary = ( IDictionary < string , object > ) value ;
435448 return new CustomValueType (
436- ( string ) dictionary [ "Name" ] ,
437- ( int ) ( long ) dictionary [ "Value" ]
449+ ( string ) dictionary [ "Name" ] ,
450+ ( int ) ( long ) dictionary [ "Value" ]
438451 ) ;
439452 }
440453
441- public object ToFirestore ( CustomValueType value ) {
454+ public override object ToFirestore ( CustomValueType value ) {
442455 return new Dictionary < string , object >
443456 {
444457 { "Name" , value . Name } ,
@@ -455,7 +468,7 @@ internal struct StructModel : IEquatable<StructModel> {
455468 public int Value { get ; set ; }
456469
457470 public override int GetHashCode ( ) { return Name . GetHashCode ( ) + Value ; }
458- public override bool Equals ( object obj ) { return obj is StructModel && Equals ( ( StructModel ) obj ) ; }
471+ public override bool Equals ( object obj ) { return obj is StructModel && Equals ( ( StructModel ) obj ) ; }
459472 public bool Equals ( StructModel other ) { return Name == other . Name && Value == other . Value ; }
460473
461474 public override string ToString ( ) { return String . Format ( "StructModel: {0}" , new { Name , Value } ) ; }
0 commit comments