2 // BinaryFormatterTest.cs - Unit tests for
3 // System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
32 using System.Runtime.Serialization;
33 using System.Runtime.Serialization.Formatters;
34 using System.Runtime.Serialization.Formatters.Binary;
35 using System.Reflection;
37 using NUnit.Framework;
39 namespace MonoTests.System.Runtime.Serialization.Formatters.Binary
42 public class SerializationTest
48 public SerializationTest (bool b, int i)
55 get { return boolean; }
56 set { boolean = value; }
60 get { return integer; }
61 set { integer = value; }
68 public class QualifiedFieldTest
74 set { this.value = value; }
82 public class QualifiedFieldTest : NestedA.QualifiedFieldTest
88 set { this.value = value; }
94 public class QualifiedFieldTest : NestedB.QualifiedFieldTest
100 set { this.value = value; }
104 class SurrogateSelector: ISurrogateSelector
106 public void ChainSelector (ISurrogateSelector selector)
110 public ISurrogateSelector GetNextSelector ()
115 public ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector)
123 sealed class ThisObjectReference : IObjectReference
125 internal static int Count;
127 internal ThisObjectReference()
131 public object GetRealObject(StreamingContext context)
139 sealed class NewObjectReference : IObjectReference
141 internal static int Count;
143 internal NewObjectReference()
147 public object GetRealObject(StreamingContext context)
150 return new NewObjectReference();
157 private int privateFoo;
158 protected int familyFoo;
159 protected internal int familyANDAssemFoo;
160 public int publicFoo;
161 internal int assemblyFoo;
163 public int PrivateFoo {
164 get { return privateFoo; }
167 public int FamilyFoo {
168 get { return familyFoo; }
171 public int FamilyANDAssemFoo {
172 get { return familyANDAssemFoo; }
175 public int PublicFoo {
176 get { return publicFoo; }
179 public int AssemblyFoo {
180 get { return assemblyFoo; }
183 public virtual void Init ()
187 familyANDAssemFoo = 4;
196 private int privateBar;
197 protected int familyBar;
198 protected internal int familyANDAssemBar;
199 public int publicBar;
200 internal int assemblyBar;
202 public int PrivateBar {
203 get { return privateBar; }
206 public int FamilyBar {
207 get { return familyBar; }
210 public int FamilyANDAssemBar {
211 get { return familyANDAssemBar; }
214 public int PublicBar {
215 get { return publicBar; }
218 public int AssemblyBar {
219 get { return assemblyBar; }
222 public override void Init ()
226 familyANDAssemBar = 4;
235 public class Comparable
242 public override bool Equals (object obj)
244 var other = obj as Comparable;
247 return other.Foo == Foo;
250 public override int GetHashCode ()
260 public virtual Instance NewInstance()
262 return new Instance { Class = this };
273 class ClassSerializationProxy : IObjectReference
277 public ClassSerializationProxy (Class klass)
279 this.className = klass.Name;
282 public object GetRealObject(StreamingContext context)
284 return new Class { Name = className };
289 class ObjectStreamClass : Class, IObjectReference, ISerializable
293 public ObjectStreamClass (Class klass)
298 public ObjectStreamClass(SerializationInfo info, StreamingContext context)
300 klass = (Class)info.GetValue("0", typeof(object));
303 public object GetRealObject (StreamingContext context)
308 public void GetObjectData (SerializationInfo info, StreamingContext context)
310 info.AddValue ("0", new ClassSerializationProxy (klass));
313 public override Instance NewInstance()
315 return klass.NewInstance();
320 class DynamicProxy: IObjectReference, ISerializable
324 public DynamicProxy (Instance obj)
329 public DynamicProxy (SerializationInfo info, StreamingContext context)
331 ObjectStreamClass osc = (ObjectStreamClass) info.GetValue("0", typeof(object));
332 obj = osc.NewInstance();
335 public object GetRealObject (StreamingContext context)
340 public void GetObjectData (SerializationInfo info, StreamingContext context)
342 info.AddValue ("0", new ObjectStreamClass (obj.Class));
347 public class BinaryFormatterTest
350 public void Constructor_Default ()
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");
362 public void Constructor ()
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");
375 public void Inheritance ()
377 MemoryStream ms = new MemoryStream ();
378 BinaryFormatter bf = new BinaryFormatter ();
380 Bar bar = new Bar ();
383 bf.Serialize (ms, bar);
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");
400 public void SerializationRoundtrip ()
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");
410 public void SerializationUnsafeRoundtrip ()
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");
420 public void NestedObjectReference ()
422 MemoryStream ms = new MemoryStream();
423 BinaryFormatter bf = new BinaryFormatter();
425 bf.Serialize(ms, new ThisObjectReference());
426 bf.Serialize(ms, new NewObjectReference());
428 Assert.AreEqual (0, ThisObjectReference.Count, "#1");
431 Assert.AreEqual (2, ThisObjectReference.Count, "#2");
432 Assert.AreEqual (0, NewObjectReference.Count, "#3");
435 } catch (SerializationException) {
437 Assert.AreEqual (101, NewObjectReference.Count, "#4");
441 public void DateTimeArray ()
443 DateTime [] e = new DateTime [6];
444 string [] names = new string [6];
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;
453 BinaryFormatter bf = new BinaryFormatter ();
454 MemoryStream ms = new MemoryStream ();
456 bf.Serialize (ms, e);
459 DateTime [] a = (DateTime []) bf.Deserialize (ms);
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]);
467 public void GenericArray ()
469 Comparable [] a = new Comparable [1];
470 a [0] = new Comparable ();
472 BinaryFormatter bf = new BinaryFormatter ();
473 MemoryStream ms = new MemoryStream ();
475 bf.Serialize (ms, a);
478 Comparable [] b = (Comparable []) bf.Deserialize (ms);
480 Assert.AreEqual (a.Length, b.Length, "#1");
481 Assert.AreEqual (a [0], b [0], "#2");
484 public Stream GetSerializedStream ()
486 SerializationTest test = new SerializationTest (true, Int32.MinValue);
487 BinaryFormatter bf = new BinaryFormatter ();
488 MemoryStream ms = new MemoryStream ();
489 bf.Serialize (ms, test);
495 public void QualifiedField()
497 QualifiedFieldTest a = new QualifiedFieldTest ();
501 Stream ms = new MemoryStream ();
502 BinaryFormatter bf = new BinaryFormatter ();
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");
513 public void SerializationBindToName ()
515 BinaryFormatter bf = new BinaryFormatter ();
516 bf.AssemblyFormat = FormatterAssemblyStyle.Full;
517 bf.Binder = new SimpleSerializationBinder ();
518 MemoryStream ms = new MemoryStream ();
520 SimpleSerializableObject o = new SimpleSerializableObject ();
521 o.Name = "MonoObject";
524 bf.Serialize (ms, o);
527 o = (SimpleSerializableObject)bf.Deserialize (ms);
528 Assert.AreEqual ("MonoObject", o.Name);
529 Assert.AreEqual (666, o.Id);
532 class SimpleSerializationBinder : SerializationBinder
534 public override Type BindToType (string assemblyName, string typeName)
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");
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");
548 // No need to call Type.GetType
549 return typeof (SimpleSerializableObject);
552 public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
554 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
555 aname.Version = new Version (9, 9, 9, 9);
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");
565 class SimpleSerializableObject
567 public string Name { get; set; }
568 public int Id { get; set; }
572 public void SerializationBindToName2 ()
574 BinaryFormatter bf = new BinaryFormatter ();
575 bf.AssemblyFormat = FormatterAssemblyStyle.Full;
576 bf.Binder = new SimpleSerializationBinder2 ();
577 MemoryStream ms = new MemoryStream ();
579 SimpleISerializableObject o = new SimpleISerializableObject ();
580 o.Name = "MonoObject";
583 bf.Serialize (ms, o);
586 o = (SimpleISerializableObject)bf.Deserialize (ms);
587 Assert.AreEqual ("MonoObject", o.Name);
588 Assert.AreEqual (666, o.Id);
594 public void NestedObjectReferences ()
596 MemoryStream ms = new MemoryStream ();
598 var cls = new Class { Name = "MyClass" };
599 var ob = cls.NewInstance ();
601 BinaryFormatter bf = new BinaryFormatter();
602 bf.Serialize (ms, new DynamicProxy (ob));
606 Instance ins = (Instance) bf.Deserialize (ms);
607 Assert.AreEqual ("MyClass", ins.Class.Name);
610 class SimpleSerializationBinder2 : SerializationBinder
612 public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
614 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
615 aname.Version = new Version (9, 9, 9, 9);
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");
623 public override Type BindToType (string assemblyName, string typeName)
625 // We *should* be getting a SimpleISerializableObject2 instance
626 if (!typeName.EndsWith ("SimpleISerializableObject2"))
627 Assert.Fail ("#BindToType-TypeName");
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");
636 return typeof (SimpleISerializableObject);
641 class SimpleISerializableObject : ISerializable
643 public string Name { get; set; }
644 public int Id { get; set; }
646 public SimpleISerializableObject ()
650 protected SimpleISerializableObject (SerializationInfo info, StreamingContext context)
652 Name = info.GetString ("Name");
653 Id = info.GetInt32 ("Id");
656 public void GetObjectData (SerializationInfo info, StreamingContext context)
658 info.AddValue ("Name", Name);
659 info.AddValue ("Id", Id);
664 public class OtherClass
669 public class BaseClass
671 public OtherClass Other { get; set; }
674 public class CustomSerBinder: SerializationBinder
676 public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
679 if (serializedType == typeof (BaseClass))
681 else if (serializedType == typeof (OtherClass))
684 throw new ArgumentException ("Unknown type", "serializedType");
687 public override Type BindToType (string assemblyName, string typeName)
691 return typeof (BaseClass);
693 return typeof (OtherClass);
695 throw new ArgumentException ("Unknown type name", "typeName");
701 public void BinderShouldBeUsedForProperties ()
703 using (var serStream = new MemoryStream ()) {
704 var binder = new CustomSerBinder ();
707 var original = new BaseClass () {
708 Other = new OtherClass ()
710 var formatter = new BinaryFormatter ();
711 formatter.Binder = binder;
712 formatter.Serialize (serStream, original);
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);
720 Assert.AreEqual (original.GetType (), deserialized.GetType ());
721 Assert.AreEqual (original.Other.GetType (), ((BaseClass)deserialized).Other.GetType ());