Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[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         class SurrogateSelector: ISurrogateSelector
66         {
67                 public void ChainSelector (ISurrogateSelector selector)
68                 {
69                 }
70
71                 public ISurrogateSelector GetNextSelector ()
72                 {
73                         return null;
74                 }
75
76                 public ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector)
77                 {
78                         selector = null;
79                         return null;
80                 }
81         }
82
83         [Serializable]
84         sealed class ThisObjectReference : IObjectReference
85         {
86                 internal static int Count;
87
88                 internal ThisObjectReference()
89                 {
90                 }
91
92                 public object GetRealObject(StreamingContext context)
93                 {
94                         Count++;
95                         return this;
96                 }
97         }
98
99         [Serializable]
100         sealed class NewObjectReference : IObjectReference
101         {
102                 internal static int Count;
103
104                 internal NewObjectReference()
105                 {
106                 }
107
108                 public object GetRealObject(StreamingContext context)
109                 {
110                         Count++;
111                         return new NewObjectReference();
112                 }
113         }
114
115         [Serializable]
116         class Foo
117         {
118                 private int privateFoo;
119                 protected int familyFoo;
120                 protected internal int familyANDAssemFoo;
121                 public int publicFoo;
122                 internal int assemblyFoo;
123
124                 public int PrivateFoo {
125                         get { return privateFoo; }
126                 }
127
128                 public int FamilyFoo {
129                         get { return familyFoo; }
130                 }
131
132                 public int FamilyANDAssemFoo {
133                         get { return familyANDAssemFoo; }
134                 }
135
136                 public int PublicFoo {
137                         get { return publicFoo; }
138                 }
139
140                 public int AssemblyFoo {
141                         get { return assemblyFoo; }
142                 }
143
144                 public virtual void Init ()
145                 {
146                         privateFoo = 1;
147                         familyFoo = 2;
148                         familyANDAssemFoo = 4;
149                         publicFoo = 8;
150                         assemblyFoo = 16;
151                 }
152         }
153
154         [Serializable]
155         class Bar : Foo
156         {
157                 private int privateBar;
158                 protected int familyBar;
159                 protected internal int familyANDAssemBar;
160                 public int publicBar;
161                 internal int assemblyBar;
162
163                 public int PrivateBar {
164                         get { return privateBar; }
165                 }
166
167                 public int FamilyBar {
168                         get { return familyBar; }
169                 }
170
171                 public int FamilyANDAssemBar {
172                         get { return familyANDAssemBar; }
173                 }
174
175                 public int PublicBar {
176                         get { return publicBar; }
177                 }
178
179                 public int AssemblyBar {
180                         get { return assemblyBar; }
181                 }
182
183                 public override void Init ()
184                 {
185                         privateBar = 1;
186                         familyBar = 2;
187                         familyANDAssemBar = 4;
188                         publicBar = 8;
189                         assemblyBar = 16;
190
191                         base.Init ();
192                 }
193         }
194
195         [Serializable]
196         public class Comparable
197         {
198                 public int Foo {
199                         get;
200                         set;
201                 }
202
203                 public override bool Equals (object obj)
204                 {
205                         var other = obj as Comparable;
206                         if (other == null)
207                                 return false;
208                         return other.Foo == Foo;
209                 }
210
211                 public override int GetHashCode ()
212                 {
213                         return Foo;
214                 }
215         }
216
217         class Class
218         {
219                 public string Name;
220
221                 public virtual Instance NewInstance()
222                 {
223                         return new Instance { Class = this };
224                 }
225         }
226
227         class Instance
228         {
229                 public Class Class;
230         }
231
232
233         [Serializable]
234         class ClassSerializationProxy : IObjectReference
235         {
236                 string className;
237
238                 public ClassSerializationProxy (Class klass)
239                 {
240                         this.className = klass.Name;
241                 }
242
243                 public object GetRealObject(StreamingContext context)
244                 {
245                         return new Class { Name = className };
246                 }
247         }
248
249         [Serializable]
250         class ObjectStreamClass : Class, IObjectReference, ISerializable
251         {
252                 Class klass;
253
254                 public ObjectStreamClass (Class klass)
255                 {
256                         this.klass = klass;
257                 }
258
259                 public ObjectStreamClass(SerializationInfo info, StreamingContext context)
260                 {
261                         klass = (Class)info.GetValue("0", typeof(object));
262                 }
263
264                 public object GetRealObject (StreamingContext context)
265                 {
266                         return this;
267                 }
268
269                 public void GetObjectData (SerializationInfo info, StreamingContext context)
270                 {
271                         info.AddValue ("0", new ClassSerializationProxy (klass));
272                 }
273
274                 public override Instance NewInstance()
275                 {
276                         return klass.NewInstance();
277                 }
278         }
279
280         [Serializable]
281         class DynamicProxy: IObjectReference, ISerializable
282         {
283                 Instance obj;
284
285                 public DynamicProxy (Instance obj)
286                 {
287                         this.obj = obj;
288                 }
289
290                 public DynamicProxy (SerializationInfo info, StreamingContext context)
291                 {
292                         ObjectStreamClass osc = (ObjectStreamClass) info.GetValue("0", typeof(object));
293                         obj = osc.NewInstance();
294                 }
295
296                 public object GetRealObject (StreamingContext context)
297                 {
298                         return obj;
299                 }
300
301                 public void GetObjectData (SerializationInfo info, StreamingContext context)
302                 {
303                         info.AddValue ("0", new ObjectStreamClass (obj.Class));
304                 }
305         }
306
307         [TestFixture]
308         public class BinaryFormatterTest
309         {
310                 [Test]
311                 public void Constructor_Default ()
312                 {
313                         BinaryFormatter bf = new BinaryFormatter ();
314 #if NET_2_0
315                         Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
316 #else
317                         Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
318 #endif
319                         Assert.IsNull (bf.Binder, "Binder");
320                         Assert.AreEqual (StreamingContextStates.All, bf.Context.State, "Context");
321                         Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
322                         Assert.IsNull (bf.SurrogateSelector, "SurrogateSelector");
323                         Assert.AreEqual (FormatterTypeStyle.TypesAlways, bf.TypeFormat, "TypeFormat");
324                 }
325
326                 [Test]
327                 public void Constructor ()
328                 {
329                         SurrogateSelector ss = new SurrogateSelector ();
330                         BinaryFormatter bf = new BinaryFormatter (ss, new StreamingContext (StreamingContextStates.CrossMachine));
331 #if NET_2_0
332                         Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
333 #else
334                         Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
335 #endif
336                         Assert.IsNull (bf.Binder, "Binder");
337                         Assert.AreEqual (StreamingContextStates.CrossMachine, bf.Context.State, "Context");
338                         Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
339                         Assert.AreSame (ss, bf.SurrogateSelector, "SurrogateSelector");
340                         Assert.AreEqual (FormatterTypeStyle.TypesAlways, bf.TypeFormat, "TypeFormat");
341                 }
342
343                 [Test]
344                 public void Inheritance ()
345                 {
346                         MemoryStream ms = new MemoryStream ();
347                         BinaryFormatter bf = new BinaryFormatter ();
348
349                         Bar bar = new Bar ();
350                         bar.Init ();
351
352                         bf.Serialize (ms, bar);
353                         ms.Position = 0;
354
355                         Bar clone = (Bar) bf.Deserialize (ms);
356                         Assert.AreEqual (bar.PrivateBar, clone.PrivateBar, "#1");
357                         Assert.AreEqual (bar.FamilyBar, clone.FamilyBar, "#2");
358                         Assert.AreEqual (bar.FamilyANDAssemBar, clone.FamilyANDAssemBar, "#3");
359                         Assert.AreEqual (bar.PublicBar, clone.PublicBar, "#4");
360                         Assert.AreEqual (bar.AssemblyBar, clone.AssemblyBar, "#5");
361                         Assert.AreEqual (bar.PrivateFoo, clone.PrivateFoo, "#6");
362                         Assert.AreEqual (bar.FamilyFoo, clone.FamilyFoo, "#7");
363                         Assert.AreEqual (bar.FamilyANDAssemFoo, clone.FamilyANDAssemFoo, "#8");
364                         Assert.AreEqual (bar.PublicFoo, clone.PublicFoo, "#9");
365                         Assert.AreEqual (bar.AssemblyFoo, clone.AssemblyFoo, "#10");
366                 }
367
368                 [Test]
369                 public void SerializationRoundtrip ()
370                 {
371                         Stream s = GetSerializedStream ();
372                         BinaryFormatter bf = new BinaryFormatter ();
373                         SerializationTest clone = (SerializationTest) bf.Deserialize (s);
374                         Assert.AreEqual (Int32.MinValue, clone.Integer, "Integer");
375                         Assert.IsFalse (clone.Boolean, "Boolean");
376                 }
377
378                 [Test]
379                 public void SerializationUnsafeRoundtrip ()
380                 {
381                         Stream s = GetSerializedStream ();
382                         BinaryFormatter bf = new BinaryFormatter ();
383                         SerializationTest clone = (SerializationTest) bf.UnsafeDeserialize (s, null);
384                         Assert.AreEqual (Int32.MinValue, clone.Integer, "Integer");
385                         Assert.IsFalse (clone.Boolean, "Boolean");
386                 }
387                 
388                 [Test]
389                 public void NestedObjectReference ()
390                 {
391                         MemoryStream ms = new MemoryStream();
392                         BinaryFormatter bf = new BinaryFormatter();
393
394                         bf.Serialize(ms, new ThisObjectReference());
395                         bf.Serialize(ms, new NewObjectReference());
396                         ms.Position = 0;
397                         Assert.AreEqual (0, ThisObjectReference.Count, "#1");
398
399                         bf.Deserialize(ms);
400                         Assert.AreEqual (2, ThisObjectReference.Count, "#2");
401                         Assert.AreEqual (0, NewObjectReference.Count, "#3");
402                         try {
403                                 bf.Deserialize(ms);
404                         } catch (SerializationException) {
405                         }
406                         Assert.AreEqual (101, NewObjectReference.Count, "#4");
407                 }
408
409                 [Test]
410                 public void DateTimeArray ()
411                 {
412                         DateTime [] e = new DateTime [6];
413                         string [] names = new string [6];
414
415                         names [0] = "Today";  e [0] = DateTime.Today;
416                         names [1] = "Min";    e [1] = DateTime.MinValue;
417                         names [2] = "Max";    e [2] = DateTime.MaxValue;
418                         names [3] = "BiCent"; e [3] = new DateTime (1976, 07, 04);
419                         names [4] = "Now";    e [4] = DateTime.Now;
420                         names [5] = "UtcNow"; e [5] = DateTime.UtcNow;
421
422                         BinaryFormatter bf = new BinaryFormatter ();
423                         MemoryStream ms = new MemoryStream ();
424
425                         bf.Serialize (ms, e);
426
427                         ms.Position = 0;
428                         DateTime [] a = (DateTime []) bf.Deserialize (ms);
429
430                         Assert.AreEqual (e.Length, a.Length);
431                         for (int i = 0; i < e.Length; ++i)
432                                 Assert.AreEqual (e [i], a [i], names [i]);
433                 }
434
435                 [Test]
436                 public void GenericArray ()
437                 {
438                         Comparable [] a = new Comparable [1];
439                         a [0] = new Comparable ();
440
441                         BinaryFormatter bf = new BinaryFormatter ();
442                         MemoryStream ms = new MemoryStream ();
443
444                         bf.Serialize (ms, a);
445
446                         ms.Position = 0;
447                         Comparable [] b = (Comparable []) bf.Deserialize (ms);
448
449                         Assert.AreEqual (a.Length, b.Length, "#1");
450                         Assert.AreEqual (a [0], b [0], "#2");
451                 }
452
453                 public Stream GetSerializedStream ()
454                 {
455                         SerializationTest test = new SerializationTest (true, Int32.MinValue);
456                         BinaryFormatter bf = new BinaryFormatter ();
457                         MemoryStream ms = new MemoryStream ();
458                         bf.Serialize (ms, test);
459                         ms.Position = 0;
460                         return ms;
461                 }
462
463 #if NET_4_0
464                 [Test]
465                 public void SerializationBindToName ()
466                 {
467                         BinaryFormatter bf = new BinaryFormatter ();
468                         bf.AssemblyFormat = FormatterAssemblyStyle.Full;
469                         bf.Binder = new SimpleSerializationBinder ();
470                         MemoryStream ms = new MemoryStream ();
471
472                         SimpleSerializableObject o = new SimpleSerializableObject ();
473                         o.Name = "MonoObject";
474                         o.Id = 666;
475
476                         bf.Serialize (ms, o);
477                         ms.Position = 0;
478
479                         o = (SimpleSerializableObject)bf.Deserialize (ms);
480                         Assert.AreEqual ("MonoObject", o.Name);
481                         Assert.AreEqual (666, o.Id);
482                 }
483
484                 class SimpleSerializationBinder : SerializationBinder
485                 {
486                         public override Type BindToType (string assemblyName, string typeName)
487                         {
488                                 // We *should* be getting a SimpleSerializableObject2 instance
489                                 // Otherwise it means we are not getting called our BindToName method.
490                                 if (!typeName.EndsWith ("SimpleSerializableObject2"))
491                                         Assert.Fail ("#BindToType-TypeName");
492
493                                 // We are also supposed to be getting a 9.9.9.9 version here,
494                                 // and if we get a different version, it likely means BindToName was called.
495                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
496                                 aname.Version = new Version (9, 9, 9, 9);
497                                 if (aname.ToString () != assemblyName)
498                                         Assert.Fail ("#BindToType-AssemblyName");
499
500                                 // No need to call Type.GetType
501                                 return typeof (SimpleSerializableObject);
502                         }
503
504                         public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
505                         {
506                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
507                                 aname.Version = new Version (9, 9, 9, 9);
508
509                                 // Serialize mapping to this same assembly with 9.9.9.9 version
510                                 // and a different type name.
511                                 assemblyName = aname.ToString ();
512                                 typeName = serializedType.FullName.Replace ("SimpleSerializableObject", "SimpleSerializableObject2");
513                         }
514                 }
515
516                 [Serializable]
517                 class SimpleSerializableObject
518                 {
519                         public string Name { get; set; }
520                         public int Id { get; set; }
521                 }
522
523                 [Test]
524                 public void SerializationBindToName2 ()
525                 {
526                         BinaryFormatter bf = new BinaryFormatter ();
527                         bf.AssemblyFormat = FormatterAssemblyStyle.Full;
528                         bf.Binder = new SimpleSerializationBinder2 ();
529                         MemoryStream ms = new MemoryStream ();
530
531                         SimpleISerializableObject o = new SimpleISerializableObject ();
532                         o.Name = "MonoObject";
533                         o.Id = 666;
534
535                         bf.Serialize (ms, o);
536                         ms.Position = 0;
537
538                         o = (SimpleISerializableObject)bf.Deserialize (ms);
539                         Assert.AreEqual ("MonoObject", o.Name);
540                         Assert.AreEqual (666, o.Id);
541
542                         ms.Close ();
543                 }
544
545                 [Test]
546                 public void NestedObjectReferences ()
547                 {
548                         MemoryStream ms = new MemoryStream ();
549
550                         var cls = new Class { Name = "MyClass" };
551                         var ob = cls.NewInstance ();
552
553                         BinaryFormatter bf = new BinaryFormatter();
554                         bf.Serialize (ms, new DynamicProxy (ob));
555
556                         ms.Position = 0;
557
558                         Instance ins = (Instance) bf.Deserialize (ms);
559                         Assert.AreEqual ("MyClass", ins.Class.Name);
560                 }
561
562                 class SimpleSerializationBinder2 : SerializationBinder
563                 {
564                         public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
565                         {
566                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
567                                 aname.Version = new Version (9, 9, 9, 9);
568
569                                 // Serialize mapping to this same assembly with 9.9.9.9 version
570                                 // and a different type name.
571                                 assemblyName = aname.ToString ();
572                                 typeName = serializedType.FullName.Replace ("SimpleISerializableObject", "SimpleISerializableObject2");
573                         }
574
575                         public override Type BindToType (string assemblyName, string typeName)
576                         {
577                                 // We *should* be getting a SimpleISerializableObject2 instance
578                                 if (!typeName.EndsWith ("SimpleISerializableObject2"))
579                                         Assert.Fail ("#BindToType-TypeName");
580
581                                 // We are also supposed to be getting a 9.9.9.9 version here,
582                                 // and if we get a different version, it likely means BindToName was called.
583                                 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
584                                 aname.Version = new Version (9, 9, 9, 9);
585                                 if (aname.ToString () != assemblyName)
586                                         Assert.Fail ("#BindToType-AssemblyName");
587
588                                 return typeof (SimpleISerializableObject);
589                         }
590                 }
591
592                 [Serializable]
593                 class SimpleISerializableObject : ISerializable
594                 {
595                         public string Name { get; set; }
596                         public int Id { get; set; }
597
598                         public SimpleISerializableObject ()
599                         {
600                         }
601
602                         protected SimpleISerializableObject (SerializationInfo info, StreamingContext context)
603                         {
604                                 Name = info.GetString ("Name");
605                                 Id = info.GetInt32 ("Id");
606                         }
607
608                         public void GetObjectData (SerializationInfo info, StreamingContext context)
609                         {
610                                 info.AddValue ("Name", Name);
611                                 info.AddValue ("Id", Id);
612                         }
613                 }
614 #endif
615         }
616 }