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; }
65 class SurrogateSelector: ISurrogateSelector
67 public void ChainSelector (ISurrogateSelector selector)
71 public ISurrogateSelector GetNextSelector ()
76 public ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector)
84 sealed class ThisObjectReference : IObjectReference
86 internal static int Count;
88 internal ThisObjectReference()
92 public object GetRealObject(StreamingContext context)
100 sealed class NewObjectReference : IObjectReference
102 internal static int Count;
104 internal NewObjectReference()
108 public object GetRealObject(StreamingContext context)
111 return new NewObjectReference();
118 private int privateFoo;
119 protected int familyFoo;
120 protected internal int familyANDAssemFoo;
121 public int publicFoo;
122 internal int assemblyFoo;
124 public int PrivateFoo {
125 get { return privateFoo; }
128 public int FamilyFoo {
129 get { return familyFoo; }
132 public int FamilyANDAssemFoo {
133 get { return familyANDAssemFoo; }
136 public int PublicFoo {
137 get { return publicFoo; }
140 public int AssemblyFoo {
141 get { return assemblyFoo; }
144 public virtual void Init ()
148 familyANDAssemFoo = 4;
157 private int privateBar;
158 protected int familyBar;
159 protected internal int familyANDAssemBar;
160 public int publicBar;
161 internal int assemblyBar;
163 public int PrivateBar {
164 get { return privateBar; }
167 public int FamilyBar {
168 get { return familyBar; }
171 public int FamilyANDAssemBar {
172 get { return familyANDAssemBar; }
175 public int PublicBar {
176 get { return publicBar; }
179 public int AssemblyBar {
180 get { return assemblyBar; }
183 public override void Init ()
187 familyANDAssemBar = 4;
196 public class Comparable
203 public override bool Equals (object obj)
205 var other = obj as Comparable;
208 return other.Foo == Foo;
211 public override int GetHashCode ()
221 public virtual Instance NewInstance()
223 return new Instance { Class = this };
234 class ClassSerializationProxy : IObjectReference
238 public ClassSerializationProxy (Class klass)
240 this.className = klass.Name;
243 public object GetRealObject(StreamingContext context)
245 return new Class { Name = className };
250 class ObjectStreamClass : Class, IObjectReference, ISerializable
254 public ObjectStreamClass (Class klass)
259 public ObjectStreamClass(SerializationInfo info, StreamingContext context)
261 klass = (Class)info.GetValue("0", typeof(object));
264 public object GetRealObject (StreamingContext context)
269 public void GetObjectData (SerializationInfo info, StreamingContext context)
271 info.AddValue ("0", new ClassSerializationProxy (klass));
274 public override Instance NewInstance()
276 return klass.NewInstance();
281 class DynamicProxy: IObjectReference, ISerializable
285 public DynamicProxy (Instance obj)
290 public DynamicProxy (SerializationInfo info, StreamingContext context)
292 ObjectStreamClass osc = (ObjectStreamClass) info.GetValue("0", typeof(object));
293 obj = osc.NewInstance();
296 public object GetRealObject (StreamingContext context)
301 public void GetObjectData (SerializationInfo info, StreamingContext context)
303 info.AddValue ("0", new ObjectStreamClass (obj.Class));
308 public class BinaryFormatterTest
311 public void Constructor_Default ()
313 BinaryFormatter bf = new BinaryFormatter ();
315 Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
317 Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
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");
327 public void Constructor ()
329 SurrogateSelector ss = new SurrogateSelector ();
330 BinaryFormatter bf = new BinaryFormatter (ss, new StreamingContext (StreamingContextStates.CrossMachine));
332 Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
334 Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
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");
344 public void Inheritance ()
346 MemoryStream ms = new MemoryStream ();
347 BinaryFormatter bf = new BinaryFormatter ();
349 Bar bar = new Bar ();
352 bf.Serialize (ms, bar);
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");
369 public void SerializationRoundtrip ()
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");
379 public void SerializationUnsafeRoundtrip ()
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");
389 public void NestedObjectReference ()
391 MemoryStream ms = new MemoryStream();
392 BinaryFormatter bf = new BinaryFormatter();
394 bf.Serialize(ms, new ThisObjectReference());
395 bf.Serialize(ms, new NewObjectReference());
397 Assert.AreEqual (0, ThisObjectReference.Count, "#1");
400 Assert.AreEqual (2, ThisObjectReference.Count, "#2");
401 Assert.AreEqual (0, NewObjectReference.Count, "#3");
404 } catch (SerializationException) {
406 Assert.AreEqual (101, NewObjectReference.Count, "#4");
410 public void DateTimeArray ()
412 DateTime [] e = new DateTime [6];
413 string [] names = new string [6];
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;
422 BinaryFormatter bf = new BinaryFormatter ();
423 MemoryStream ms = new MemoryStream ();
425 bf.Serialize (ms, e);
428 DateTime [] a = (DateTime []) bf.Deserialize (ms);
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]);
436 public void GenericArray ()
438 Comparable [] a = new Comparable [1];
439 a [0] = new Comparable ();
441 BinaryFormatter bf = new BinaryFormatter ();
442 MemoryStream ms = new MemoryStream ();
444 bf.Serialize (ms, a);
447 Comparable [] b = (Comparable []) bf.Deserialize (ms);
449 Assert.AreEqual (a.Length, b.Length, "#1");
450 Assert.AreEqual (a [0], b [0], "#2");
453 public Stream GetSerializedStream ()
455 SerializationTest test = new SerializationTest (true, Int32.MinValue);
456 BinaryFormatter bf = new BinaryFormatter ();
457 MemoryStream ms = new MemoryStream ();
458 bf.Serialize (ms, test);
465 public void SerializationBindToName ()
467 BinaryFormatter bf = new BinaryFormatter ();
468 bf.AssemblyFormat = FormatterAssemblyStyle.Full;
469 bf.Binder = new SimpleSerializationBinder ();
470 MemoryStream ms = new MemoryStream ();
472 SimpleSerializableObject o = new SimpleSerializableObject ();
473 o.Name = "MonoObject";
476 bf.Serialize (ms, o);
479 o = (SimpleSerializableObject)bf.Deserialize (ms);
480 Assert.AreEqual ("MonoObject", o.Name);
481 Assert.AreEqual (666, o.Id);
484 class SimpleSerializationBinder : SerializationBinder
486 public override Type BindToType (string assemblyName, string typeName)
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");
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");
500 // No need to call Type.GetType
501 return typeof (SimpleSerializableObject);
504 public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
506 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
507 aname.Version = new Version (9, 9, 9, 9);
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");
517 class SimpleSerializableObject
519 public string Name { get; set; }
520 public int Id { get; set; }
524 public void SerializationBindToName2 ()
526 BinaryFormatter bf = new BinaryFormatter ();
527 bf.AssemblyFormat = FormatterAssemblyStyle.Full;
528 bf.Binder = new SimpleSerializationBinder2 ();
529 MemoryStream ms = new MemoryStream ();
531 SimpleISerializableObject o = new SimpleISerializableObject ();
532 o.Name = "MonoObject";
535 bf.Serialize (ms, o);
538 o = (SimpleISerializableObject)bf.Deserialize (ms);
539 Assert.AreEqual ("MonoObject", o.Name);
540 Assert.AreEqual (666, o.Id);
546 public void NestedObjectReferences ()
548 MemoryStream ms = new MemoryStream ();
550 var cls = new Class { Name = "MyClass" };
551 var ob = cls.NewInstance ();
553 BinaryFormatter bf = new BinaryFormatter();
554 bf.Serialize (ms, new DynamicProxy (ob));
558 Instance ins = (Instance) bf.Deserialize (ms);
559 Assert.AreEqual ("MyClass", ins.Class.Name);
562 class SimpleSerializationBinder2 : SerializationBinder
564 public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
566 AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
567 aname.Version = new Version (9, 9, 9, 9);
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");
575 public override Type BindToType (string assemblyName, string typeName)
577 // We *should* be getting a SimpleISerializableObject2 instance
578 if (!typeName.EndsWith ("SimpleISerializableObject2"))
579 Assert.Fail ("#BindToType-TypeName");
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");
588 return typeof (SimpleISerializableObject);
593 class SimpleISerializableObject : ISerializable
595 public string Name { get; set; }
596 public int Id { get; set; }
598 public SimpleISerializableObject ()
602 protected SimpleISerializableObject (SerializationInfo info, StreamingContext context)
604 Name = info.GetString ("Name");
605 Id = info.GetInt32 ("Id");
608 public void GetObjectData (SerializationInfo info, StreamingContext context)
610 info.AddValue ("Name", Name);
611 info.AddValue ("Id", Id);