Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mcs / class / corlib / Test / System.Runtime.Serialization.Formatters.Binary / BinaryFormatterTest.cs
1 //
2 // BinaryFormatterTest.cs - Unit tests for 
3 //      System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
4 //
5 // Author:
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.IO;
32 using System.Runtime.Serialization;
33 using System.Runtime.Serialization.Formatters;
34 using System.Runtime.Serialization.Formatters.Binary;
35 using System.Reflection;
36
37 using NUnit.Framework;
38
39 namespace MonoTests.System.Runtime.Serialization.Formatters.Binary
40 {
41         [Serializable]
42         public class SerializationTest
43         {
44                 private int integer;
45                 [NonSerialized]
46                 private bool boolean;
47
48                 public SerializationTest (bool b, int i)
49                 {
50                         boolean = b;
51                         integer = i;
52                 }
53
54                 public bool Boolean {
55                         get { return boolean; }
56                         set { boolean = value; }
57                 }
58
59                 public int Integer {
60                         get { return integer; }
61                         set { integer = value; }
62                 }
63         }
64
65         namespace NestedA
66         {
67                 [Serializable]
68                 public class QualifiedFieldTest
69                 {
70                         int value = 0;
71
72                         public int ValueA {
73                                 get { return value; }
74                                 set { this.value = value; }
75                         }
76                 }
77         }
78
79         namespace NestedB
80         {
81                 [Serializable]
82                 public class QualifiedFieldTest : NestedA.QualifiedFieldTest
83                 {
84                         int value = 0;
85
86                         public int ValueB {
87                                 get { return value; }
88                                 set { this.value = value; }
89                         }
90                 }
91         }
92
93         [Serializable]
94         public class QualifiedFieldTest : NestedB.QualifiedFieldTest
95         {
96                 int value = 0;
97
98                 public int Value {
99                         get { return value; }
100                         set { this.value = value; }
101                 }
102         }
103
104         class SurrogateSelector: ISurrogateSelector
105         {
106                 public void ChainSelector (ISurrogateSelector selector)
107                 {
108                 }
109
110                 public ISurrogateSelector GetNextSelector ()
111                 {
112                         return null;
113                 }
114
115                 public ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector)
116                 {
117                         selector = null;
118                         return null;
119                 }
120         }
121
122         [Serializable]
123         sealed class ThisObjectReference : IObjectReference
124         {
125                 internal static int Count;
126
127                 internal ThisObjectReference()
128                 {
129                 }
130
131                 public object GetRealObject(StreamingContext context)
132                 {
133                         Count++;
134                         return this;
135                 }
136         }
137
138         [Serializable]
139         sealed class NewObjectReference : IObjectReference
140         {
141                 internal static int Count;
142
143                 internal NewObjectReference()
144                 {
145                 }
146
147                 public object GetRealObject(StreamingContext context)
148                 {
149                         Count++;
150                         return new NewObjectReference();
151                 }
152         }
153
154         [Serializable]
155         class Foo
156         {
157                 private int privateFoo;
158                 protected int familyFoo;
159                 protected internal int familyANDAssemFoo;
160                 public int publicFoo;
161                 internal int assemblyFoo;
162
163                 public int PrivateFoo {
164                         get { return privateFoo; }
165                 }
166
167                 public int FamilyFoo {
168                         get { return familyFoo; }
169                 }
170
171                 public int FamilyANDAssemFoo {
172                         get { return familyANDAssemFoo; }
173                 }
174
175                 public int PublicFoo {
176                         get { return publicFoo; }
177                 }
178
179                 public int AssemblyFoo {
180                         get { return assemblyFoo; }
181                 }
182
183                 public virtual void Init ()
184                 {
185                         privateFoo = 1;
186                         familyFoo = 2;
187                         familyANDAssemFoo = 4;
188                         publicFoo = 8;
189                         assemblyFoo = 16;
190                 }
191         }
192
193         [Serializable]
194         class Bar : Foo
195         {
196                 private int privateBar;
197                 protected int familyBar;
198                 protected internal int familyANDAssemBar;
199                 public int publicBar;
200                 internal int assemblyBar;
201
202                 public int PrivateBar {
203                         get { return privateBar; }
204                 }
205
206                 public int FamilyBar {
207                         get { return familyBar; }
208                 }
209
210                 public int FamilyANDAssemBar {
211                         get { return familyANDAssemBar; }
212                 }
213
214                 public int PublicBar {
215                         get { return publicBar; }
216                 }
217
218                 public int AssemblyBar {
219                         get { return assemblyBar; }
220                 }
221
222                 public override void Init ()
223                 {
224                         privateBar = 1;
225                         familyBar = 2;
226                         familyANDAssemBar = 4;
227                         publicBar = 8;
228                         assemblyBar = 16;
229
230                         base.Init ();
231                 }
232         }
233
234         [Serializable]
235         public class Comparable
236         {
237                 public int Foo {
238                         get;
239                         set;
240                 }
241
242                 public override bool Equals (object obj)
243                 {
244                         var other = obj as Comparable;
245                         if (other == null)
246                                 return false;
247                         return other.Foo == Foo;
248                 }
249
250                 public override int GetHashCode ()
251                 {
252                         return Foo;
253                 }
254         }
255
256         class Class
257         {
258                 public string Name;
259
260                 public virtual Instance NewInstance()
261                 {
262                         return new Instance { Class = this };
263                 }
264         }
265
266         class Instance
267         {
268                 public Class Class;
269         }
270
271
272         [Serializable]
273         class ClassSerializationProxy : IObjectReference
274         {
275                 string className;
276
277                 public ClassSerializationProxy (Class klass)
278                 {
279                         this.className = klass.Name;
280                 }
281
282                 public object GetRealObject(StreamingContext context)
283                 {
284                         return new Class { Name = className };
285                 }
286         }
287
288         [Serializable]
289         class ObjectStreamClass : Class, IObjectReference, ISerializable
290         {
291                 Class klass;
292
293                 public ObjectStreamClass (Class klass)
294                 {
295                         this.klass = klass;
296                 }
297
298                 public ObjectStreamClass(SerializationInfo info, StreamingContext context)
299                 {
300                         klass = (Class)info.GetValue("0", typeof(object));
301                 }
302
303                 public object GetRealObject (StreamingContext context)
304                 {
305                         return this;
306                 }
307
308                 public void GetObjectData (SerializationInfo info, StreamingContext context)
309                 {
310                         info.AddValue ("0", new ClassSerializationProxy (klass));
311                 }
312
313                 public override Instance NewInstance()
314                 {
315                         return klass.NewInstance();
316                 }
317         }
318
319         [Serializable]
320         class DynamicProxy: IObjectReference, ISerializable
321         {
322                 Instance obj;
323
324                 public DynamicProxy (Instance obj)
325                 {
326                         this.obj = obj;
327                 }
328
329                 public DynamicProxy (SerializationInfo info, StreamingContext context)
330                 {
331                         ObjectStreamClass osc = (ObjectStreamClass) info.GetValue("0", typeof(object));
332                         obj = osc.NewInstance();
333                 }
334
335                 public object GetRealObject (StreamingContext context)
336                 {
337                         return obj;
338                 }
339
340                 public void GetObjectData (SerializationInfo info, StreamingContext context)
341                 {
342                         info.AddValue ("0", new ObjectStreamClass (obj.Class));
343                 }
344         }
345
346         [TestFixture]
347         public class BinaryFormatterTest
348         {
349                 [Test]
350                 public void Constructor_Default ()
351                 {
352                         BinaryFormatter bf = new BinaryFormatter ();
353                         Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
354                         Assert.IsNull (bf.Binder, "Binder");
355                         Assert.AreEqual (StreamingContextStates.All, bf.Context.State, "Context");
356                         Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
357                         Assert.IsNull (bf.SurrogateSelector, "SurrogateSelector");
358                         Assert.AreEqual (FormatterTypeStyle.TypesAlways, bf.TypeFormat, "TypeFormat");
359                 }
360
361                 [Test]
362                 public void Constructor ()
363                 {
364                         SurrogateSelector ss = new SurrogateSelector ();
365                         BinaryFormatter bf = new BinaryFormatter (ss, new StreamingContext (StreamingContextStates.CrossMachine));
366                         Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
367                         Assert.IsNull (bf.Binder, "Binder");
368                         Assert.AreEqual (StreamingContextStates.CrossMachine, bf.Context.State, "Context");
369                         Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
370                         Assert.AreSame (ss, bf.SurrogateSelector, "SurrogateSelector");
371                         Assert.AreEqual (FormatterTypeStyle.TypesAlways, bf.TypeFormat, "TypeFormat");
372                 }
373
374                 [Test]
375                 public void Inheritance ()
376                 {
377                         MemoryStream ms = new MemoryStream ();
378                         BinaryFormatter bf = new BinaryFormatter ();
379
380                         Bar bar = new Bar ();
381                         bar.Init ();
382
383                         bf.Serialize (ms, bar);
384                         ms.Position = 0;
385
386                         Bar clone = (Bar) bf.Deserialize (ms);
387                         Assert.AreEqual (bar.PrivateBar, clone.PrivateBar, "#1");
388                         Assert.AreEqual (bar.FamilyBar, clone.FamilyBar, "#2");
389                         Assert.AreEqual (bar.FamilyANDAssemBar, clone.FamilyANDAssemBar, "#3");
390                         Assert.AreEqual (bar.PublicBar, clone.PublicBar, "#4");
391                         Assert.AreEqual (bar.AssemblyBar, clone.AssemblyBar, "#5");
392                         Assert.AreEqual (bar.PrivateFoo, clone.PrivateFoo, "#6");
393                         Assert.AreEqual (bar.FamilyFoo, clone.FamilyFoo, "#7");
394                         Assert.AreEqual (bar.FamilyANDAssemFoo, clone.FamilyANDAssemFoo, "#8");
395                         Assert.AreEqual (bar.PublicFoo, clone.PublicFoo, "#9");
396                         Assert.AreEqual (bar.AssemblyFoo, clone.AssemblyFoo, "#10");
397                 }
398
399                 [Test]
400                 public void SerializationRoundtrip ()
401                 {
402                         Stream s = GetSerializedStream ();
403                         BinaryFormatter bf = new BinaryFormatter ();
404                         SerializationTest clone = (SerializationTest) bf.Deserialize (s);
405                         Assert.AreEqual (Int32.MinValue, clone.Integer, "Integer");
406                         Assert.IsFalse (clone.Boolean, "Boolean");
407                 }
408
409                 [Test]
410                 public void SerializationUnsafeRoundtrip ()
411                 {
412                         Stream s = GetSerializedStream ();
413                         BinaryFormatter bf = new BinaryFormatter ();
414                         SerializationTest clone = (SerializationTest) bf.UnsafeDeserialize (s, null);
415                         Assert.AreEqual (Int32.MinValue, clone.Integer, "Integer");
416                         Assert.IsFalse (clone.Boolean, "Boolean");
417                 }
418                 
419                 [Test]
420                 public void NestedObjectReference ()
421                 {
422                         MemoryStream ms = new MemoryStream();
423                         BinaryFormatter bf = new BinaryFormatter();
424
425                         bf.Serialize(ms, new ThisObjectReference());
426                         bf.Serialize(ms, new NewObjectReference());
427                         ms.Position = 0;
428                         Assert.AreEqual (0, ThisObjectReference.Count, "#1");
429
430                         bf.Deserialize(ms);
431                         Assert.AreEqual (2, ThisObjectReference.Count, "#2");
432                         Assert.AreEqual (0, NewObjectReference.Count, "#3");
433                         try {
434                                 bf.Deserialize(ms);
435                         } catch (SerializationException) {
436                         }
437                         Assert.AreEqual (101, NewObjectReference.Count, "#4");
438                 }
439
440                 [Test]
441                 public void DateTimeArray ()
442                 {
443                         DateTime [] e = new DateTime [6];
444                         string [] names = new string [6];
445
446                         names [0] = "Today";  e [0] = DateTime.Today;
447                         names [1] = "Min";    e [1] = DateTime.MinValue;
448                         names [2] = "Max";    e [2] = DateTime.MaxValue;
449                         names [3] = "BiCent"; e [3] = new DateTime (1976, 07, 04);
450                         names [4] = "Now";    e [4] = DateTime.Now;
451                         names [5] = "UtcNow"; e [5] = DateTime.UtcNow;
452
453                         BinaryFormatter bf = new BinaryFormatter ();
454                         MemoryStream ms = new MemoryStream ();
455
456                         bf.Serialize (ms, e);
457
458                         ms.Position = 0;
459                         DateTime [] a = (DateTime []) bf.Deserialize (ms);
460
461                         Assert.AreEqual (e.Length, a.Length);
462                         for (int i = 0; i < e.Length; ++i)
463                                 Assert.AreEqual (e [i], a [i], names [i]);
464                 }
465
466                 [Test]
467                 public void GenericArray ()
468                 {
469                         Comparable [] a = new Comparable [1];
470                         a [0] = new Comparable ();
471
472                         BinaryFormatter bf = new BinaryFormatter ();
473                         MemoryStream ms = new MemoryStream ();
474
475                         bf.Serialize (ms, a);
476
477                         ms.Position = 0;
478                         Comparable [] b = (Comparable []) bf.Deserialize (ms);
479
480                         Assert.AreEqual (a.Length, b.Length, "#1");
481                         Assert.AreEqual (a [0], b [0], "#2");
482                 }
483
484                 public Stream GetSerializedStream ()
485                 {
486                         SerializationTest test = new SerializationTest (true, Int32.MinValue);
487                         BinaryFormatter bf = new BinaryFormatter ();
488                         MemoryStream ms = new MemoryStream ();
489                         bf.Serialize (ms, test);
490                         ms.Position = 0;
491                         return ms;
492                 }
493
494                 [Test]
495                 public void QualifiedField()
496                 {
497                         QualifiedFieldTest a = new QualifiedFieldTest ();
498                         a.ValueA = 1;
499                         a.ValueB = 2;
500                         a.Value = 3;
501                         Stream ms = new MemoryStream ();
502                         BinaryFormatter bf = new BinaryFormatter ();
503                         bf.Serialize(ms, a);
504                         ms.Position = 0;
505                         QualifiedFieldTest b = (QualifiedFieldTest)bf.Deserialize (ms);
506                         Assert.AreEqual (a.ValueA, b.ValueA, "#1");
507                         Assert.AreEqual (a.ValueB, b.ValueB, "#2");
508                         Assert.AreEqual (a.Value, b.Value, "#3");
509                 }
510
511 #if NET_4_0
512                 [Test]
513                 public void SerializationBindToName ()
514                 {
515                         BinaryFormatter bf = new BinaryFormatter ();
516                         bf.AssemblyFormat = FormatterAssemblyStyle.Full;
517                         bf.Binder = new SimpleSerializationBinder ();
518                         MemoryStream ms = new MemoryStream ();
519
520                         SimpleSerializableObject o = new SimpleSerializableObject ();
521                         o.Name = "MonoObject";
522                         o.Id = 666;
523
524                         bf.Serialize (ms, o);
525                         ms.Position = 0;
526
527                         o = (SimpleSerializableObject)bf.Deserialize (ms);
528                         Assert.AreEqual ("MonoObject", o.Name);
529                         Assert.AreEqual (666, o.Id);
530                 }
531
532                 class SimpleSerializationBinder : SerializationBinder
533                 {
534                         public override Type BindToType (string assemblyName, string typeName)
535                         {
536                                 // We *should* be getting a SimpleSerializableObject2 instance
537                                 // Otherwise it means we are not getting called our BindToName method.
538                                 if (!typeName.EndsWith ("SimpleSerializableObject2"))
539                                         Assert.Fail ("#BindToType-TypeName");
540
541                                 // We are also supposed to be getting a 9.9.9.9 version here,
542                                 // and if we get a different version, it likely means BindToName was called.
543                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
544                                 aname.Version = new Version (9, 9, 9, 9);
545                                 if (aname.ToString () != assemblyName)
546                                         Assert.Fail ("#BindToType-AssemblyName");
547
548                                 // No need to call Type.GetType
549                                 return typeof (SimpleSerializableObject);
550                         }
551
552                         public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
553                         {
554                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
555                                 aname.Version = new Version (9, 9, 9, 9);
556
557                                 // Serialize mapping to this same assembly with 9.9.9.9 version
558                                 // and a different type name.
559                                 assemblyName = aname.ToString ();
560                                 typeName = serializedType.FullName.Replace ("SimpleSerializableObject", "SimpleSerializableObject2");
561                         }
562                 }
563
564                 [Serializable]
565                 class SimpleSerializableObject
566                 {
567                         public string Name { get; set; }
568                         public int Id { get; set; }
569                 }
570
571                 [Test]
572                 public void SerializationBindToName2 ()
573                 {
574                         BinaryFormatter bf = new BinaryFormatter ();
575                         bf.AssemblyFormat = FormatterAssemblyStyle.Full;
576                         bf.Binder = new SimpleSerializationBinder2 ();
577                         MemoryStream ms = new MemoryStream ();
578
579                         SimpleISerializableObject o = new SimpleISerializableObject ();
580                         o.Name = "MonoObject";
581                         o.Id = 666;
582
583                         bf.Serialize (ms, o);
584                         ms.Position = 0;
585
586                         o = (SimpleISerializableObject)bf.Deserialize (ms);
587                         Assert.AreEqual ("MonoObject", o.Name);
588                         Assert.AreEqual (666, o.Id);
589
590                         ms.Close ();
591                 }
592
593                 [Test]
594                 public void NestedObjectReferences ()
595                 {
596                         MemoryStream ms = new MemoryStream ();
597
598                         var cls = new Class { Name = "MyClass" };
599                         var ob = cls.NewInstance ();
600
601                         BinaryFormatter bf = new BinaryFormatter();
602                         bf.Serialize (ms, new DynamicProxy (ob));
603
604                         ms.Position = 0;
605
606                         Instance ins = (Instance) bf.Deserialize (ms);
607                         Assert.AreEqual ("MyClass", ins.Class.Name);
608                 }
609
610                 class SimpleSerializationBinder2 : SerializationBinder
611                 {
612                         public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
613                         {
614                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
615                                 aname.Version = new Version (9, 9, 9, 9);
616
617                                 // Serialize mapping to this same assembly with 9.9.9.9 version
618                                 // and a different type name.
619                                 assemblyName = aname.ToString ();
620                                 typeName = serializedType.FullName.Replace ("SimpleISerializableObject", "SimpleISerializableObject2");
621                         }
622
623                         public override Type BindToType (string assemblyName, string typeName)
624                         {
625                                 // We *should* be getting a SimpleISerializableObject2 instance
626                                 if (!typeName.EndsWith ("SimpleISerializableObject2"))
627                                         Assert.Fail ("#BindToType-TypeName");
628
629                                 // We are also supposed to be getting a 9.9.9.9 version here,
630                                 // and if we get a different version, it likely means BindToName was called.
631                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
632                                 aname.Version = new Version (9, 9, 9, 9);
633                                 if (aname.ToString () != assemblyName)
634                                         Assert.Fail ("#BindToType-AssemblyName");
635
636                                 return typeof (SimpleISerializableObject);
637                         }
638                 }
639
640                 [Serializable]
641                 class SimpleISerializableObject : ISerializable
642                 {
643                         public string Name { get; set; }
644                         public int Id { get; set; }
645
646                         public SimpleISerializableObject ()
647                         {
648                         }
649
650                         protected SimpleISerializableObject (SerializationInfo info, StreamingContext context)
651                         {
652                                 Name = info.GetString ("Name");
653                                 Id = info.GetInt32 ("Id");
654                         }
655
656                         public void GetObjectData (SerializationInfo info, StreamingContext context)
657                         {
658                                 info.AddValue ("Name", Name);
659                                 info.AddValue ("Id", Id);
660                         }
661                 }
662
663                 [Serializable]
664                 public class OtherClass
665                 {
666                 }
667
668                 [Serializable]
669                 public class BaseClass
670                 {
671                         public OtherClass Other { get; set; }
672                 }
673
674                 public class CustomSerBinder: SerializationBinder
675                 {
676                         public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
677                         {
678                                 assemblyName = null;
679                                 if (serializedType == typeof (BaseClass))
680                                         typeName = "base";
681                                 else if (serializedType == typeof (OtherClass))
682                                         typeName = "other";
683                                 else
684                                         throw new ArgumentException ("Unknown type", "serializedType");
685                         }
686
687                         public override Type BindToType (string assemblyName, string typeName)
688                         {
689                                 switch (typeName) {
690                                 case "base":
691                                         return typeof (BaseClass);
692                                 case "other":
693                                         return typeof (OtherClass);
694                                 default:
695                                         throw new ArgumentException ("Unknown type name", "typeName");
696                                 }
697                         }
698                 }
699
700                 [Test]
701                 public void BinderShouldBeUsedForProperties ()
702                 {
703                         using (var serStream = new MemoryStream ()) {
704                                 var binder = new CustomSerBinder ();
705
706                                 // serialize
707                                 var original = new BaseClass () {
708                                         Other = new OtherClass ()
709                                 };
710                                 var formatter = new BinaryFormatter ();
711                                 formatter.Binder = binder;
712                                 formatter.Serialize (serStream, original);
713
714                                 // deserialize, making sure we're using a new formatter, just to be thorough
715                                 formatter = new BinaryFormatter ();
716                                 formatter.Binder = binder;
717                                 serStream.Seek (0, SeekOrigin.Begin);
718                                 var deserialized = formatter.Deserialize (serStream);
719
720                                 Assert.AreEqual (original.GetType (), deserialized.GetType ());
721                                 Assert.AreEqual (original.Other.GetType (), ((BaseClass)deserialized).Other.GetType ());
722                         }
723                 }
724 #endif
725         }
726 }