Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mcs / class / corlib / Test / System.Runtime.Serialization.Formatters.Binary / BinaryFormatterTest.cs
index 3173e57ecbc7a241b33fa593f17de9f1bc482dc1..6d4b997fb45317b67a5c928e23f97d46332aa4e8 100644 (file)
@@ -32,13 +32,15 @@ using System.IO;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization.Formatters;
 using System.Runtime.Serialization.Formatters.Binary;
+using System.Reflection;
 
 using NUnit.Framework;
 
-namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
-
+namespace MonoTests.System.Runtime.Serialization.Formatters.Binary
+{
        [Serializable]
-       public class SerializationTest {
+       public class SerializationTest
+       {
                private int integer;
                [NonSerialized]
                private bool boolean;
@@ -60,7 +62,47 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                }
        }
 
-       class SurrogateSelector: ISurrogateSelector {
+       namespace NestedA
+       {
+               [Serializable]
+               public class QualifiedFieldTest
+               {
+                       int value = 0;
+
+                       public int ValueA {
+                               get { return value; }
+                               set { this.value = value; }
+                       }
+               }
+       }
+
+       namespace NestedB
+       {
+               [Serializable]
+               public class QualifiedFieldTest : NestedA.QualifiedFieldTest
+               {
+                       int value = 0;
+
+                       public int ValueB {
+                               get { return value; }
+                               set { this.value = value; }
+                       }
+               }
+       }
+
+       [Serializable]
+       public class QualifiedFieldTest : NestedB.QualifiedFieldTest
+       {
+               int value = 0;
+
+               public int Value {
+                       get { return value; }
+                       set { this.value = value; }
+               }
+       }
+
+       class SurrogateSelector: ISurrogateSelector
+       {
                public void ChainSelector (ISurrogateSelector selector)
                {
                }
@@ -109,18 +151,206 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                }
        }
 
-       [TestFixture]
-       public class BinaryFormatterTest {
+       [Serializable]
+       class Foo
+       {
+               private int privateFoo;
+               protected int familyFoo;
+               protected internal int familyANDAssemFoo;
+               public int publicFoo;
+               internal int assemblyFoo;
+
+               public int PrivateFoo {
+                       get { return privateFoo; }
+               }
+
+               public int FamilyFoo {
+                       get { return familyFoo; }
+               }
+
+               public int FamilyANDAssemFoo {
+                       get { return familyANDAssemFoo; }
+               }
+
+               public int PublicFoo {
+                       get { return publicFoo; }
+               }
+
+               public int AssemblyFoo {
+                       get { return assemblyFoo; }
+               }
 
+               public virtual void Init ()
+               {
+                       privateFoo = 1;
+                       familyFoo = 2;
+                       familyANDAssemFoo = 4;
+                       publicFoo = 8;
+                       assemblyFoo = 16;
+               }
+       }
+
+       [Serializable]
+       class Bar : Foo
+       {
+               private int privateBar;
+               protected int familyBar;
+               protected internal int familyANDAssemBar;
+               public int publicBar;
+               internal int assemblyBar;
+
+               public int PrivateBar {
+                       get { return privateBar; }
+               }
+
+               public int FamilyBar {
+                       get { return familyBar; }
+               }
+
+               public int FamilyANDAssemBar {
+                       get { return familyANDAssemBar; }
+               }
+
+               public int PublicBar {
+                       get { return publicBar; }
+               }
+
+               public int AssemblyBar {
+                       get { return assemblyBar; }
+               }
+
+               public override void Init ()
+               {
+                       privateBar = 1;
+                       familyBar = 2;
+                       familyANDAssemBar = 4;
+                       publicBar = 8;
+                       assemblyBar = 16;
+
+                       base.Init ();
+               }
+       }
+
+       [Serializable]
+       public class Comparable
+       {
+               public int Foo {
+                       get;
+                       set;
+               }
+
+               public override bool Equals (object obj)
+               {
+                       var other = obj as Comparable;
+                       if (other == null)
+                               return false;
+                       return other.Foo == Foo;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return Foo;
+               }
+       }
+
+       class Class
+       {
+               public string Name;
+
+               public virtual Instance NewInstance()
+               {
+                       return new Instance { Class = this };
+               }
+       }
+
+       class Instance
+       {
+               public Class Class;
+       }
+
+
+       [Serializable]
+       class ClassSerializationProxy : IObjectReference
+       {
+               string className;
+
+               public ClassSerializationProxy (Class klass)
+               {
+                       this.className = klass.Name;
+               }
+
+               public object GetRealObject(StreamingContext context)
+               {
+                       return new Class { Name = className };
+               }
+       }
+
+       [Serializable]
+       class ObjectStreamClass : Class, IObjectReference, ISerializable
+       {
+               Class klass;
+
+               public ObjectStreamClass (Class klass)
+               {
+                       this.klass = klass;
+               }
+
+               public ObjectStreamClass(SerializationInfo info, StreamingContext context)
+               {
+                       klass = (Class)info.GetValue("0", typeof(object));
+               }
+
+               public object GetRealObject (StreamingContext context)
+               {
+                       return this;
+               }
+
+               public void GetObjectData (SerializationInfo info, StreamingContext context)
+               {
+                       info.AddValue ("0", new ClassSerializationProxy (klass));
+               }
+
+               public override Instance NewInstance()
+               {
+                       return klass.NewInstance();
+               }
+       }
+
+       [Serializable]
+       class DynamicProxy: IObjectReference, ISerializable
+       {
+               Instance obj;
+
+               public DynamicProxy (Instance obj)
+               {
+                       this.obj = obj;
+               }
+
+               public DynamicProxy (SerializationInfo info, StreamingContext context)
+               {
+                       ObjectStreamClass osc = (ObjectStreamClass) info.GetValue("0", typeof(object));
+                       obj = osc.NewInstance();
+               }
+
+               public object GetRealObject (StreamingContext context)
+               {
+                       return obj;
+               }
+
+               public void GetObjectData (SerializationInfo info, StreamingContext context)
+               {
+                       info.AddValue ("0", new ObjectStreamClass (obj.Class));
+               }
+       }
+
+       [TestFixture]
+       public class BinaryFormatterTest
+       {
                [Test]
                public void Constructor_Default ()
                {
                        BinaryFormatter bf = new BinaryFormatter ();
-#if NET_2_0
                        Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
-#else
-                       Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
-#endif
                        Assert.IsNull (bf.Binder, "Binder");
                        Assert.AreEqual (StreamingContextStates.All, bf.Context.State, "Context");
                        Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
@@ -133,11 +363,7 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                {
                        SurrogateSelector ss = new SurrogateSelector ();
                        BinaryFormatter bf = new BinaryFormatter (ss, new StreamingContext (StreamingContextStates.CrossMachine));
-#if NET_2_0
                        Assert.AreEqual (FormatterAssemblyStyle.Simple, bf.AssemblyFormat, "AssemblyFormat");
-#else
-                       Assert.AreEqual (FormatterAssemblyStyle.Full, bf.AssemblyFormat, "AssemblyFormat");
-#endif
                        Assert.IsNull (bf.Binder, "Binder");
                        Assert.AreEqual (StreamingContextStates.CrossMachine, bf.Context.State, "Context");
                        Assert.AreEqual (TypeFilterLevel.Full, bf.FilterLevel, "FilterLevel");
@@ -145,14 +371,29 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                        Assert.AreEqual (FormatterTypeStyle.TypesAlways, bf.TypeFormat, "TypeFormat");
                }
 
-               public Stream GetSerializedStream ()
+               [Test]
+               public void Inheritance ()
                {
-                       SerializationTest test = new SerializationTest (true, Int32.MinValue);
-                       BinaryFormatter bf = new BinaryFormatter ();
                        MemoryStream ms = new MemoryStream ();
-                       bf.Serialize (ms, test);
+                       BinaryFormatter bf = new BinaryFormatter ();
+
+                       Bar bar = new Bar ();
+                       bar.Init ();
+
+                       bf.Serialize (ms, bar);
                        ms.Position = 0;
-                       return ms;
+
+                       Bar clone = (Bar) bf.Deserialize (ms);
+                       Assert.AreEqual (bar.PrivateBar, clone.PrivateBar, "#1");
+                       Assert.AreEqual (bar.FamilyBar, clone.FamilyBar, "#2");
+                       Assert.AreEqual (bar.FamilyANDAssemBar, clone.FamilyANDAssemBar, "#3");
+                       Assert.AreEqual (bar.PublicBar, clone.PublicBar, "#4");
+                       Assert.AreEqual (bar.AssemblyBar, clone.AssemblyBar, "#5");
+                       Assert.AreEqual (bar.PrivateFoo, clone.PrivateFoo, "#6");
+                       Assert.AreEqual (bar.FamilyFoo, clone.FamilyFoo, "#7");
+                       Assert.AreEqual (bar.FamilyANDAssemFoo, clone.FamilyANDAssemFoo, "#8");
+                       Assert.AreEqual (bar.PublicFoo, clone.PublicFoo, "#9");
+                       Assert.AreEqual (bar.AssemblyFoo, clone.AssemblyFoo, "#10");
                }
 
                [Test]
@@ -189,12 +430,9 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                        bf.Deserialize(ms);
                        Assert.AreEqual (2, ThisObjectReference.Count, "#2");
                        Assert.AreEqual (0, NewObjectReference.Count, "#3");
-                       try
-                       {
+                       try {
                                bf.Deserialize(ms);
-                       }
-                       catch (SerializationException e)
-                       {
+                       } catch (SerializationException) {
                        }
                        Assert.AreEqual (101, NewObjectReference.Count, "#4");
                }
@@ -224,5 +462,265 @@ namespace MonoTests.System.Runtime.Serialization.Formatters.Binary {
                        for (int i = 0; i < e.Length; ++i)
                                Assert.AreEqual (e [i], a [i], names [i]);
                }
+
+               [Test]
+               public void GenericArray ()
+               {
+                       Comparable [] a = new Comparable [1];
+                       a [0] = new Comparable ();
+
+                       BinaryFormatter bf = new BinaryFormatter ();
+                       MemoryStream ms = new MemoryStream ();
+
+                       bf.Serialize (ms, a);
+
+                       ms.Position = 0;
+                       Comparable [] b = (Comparable []) bf.Deserialize (ms);
+
+                       Assert.AreEqual (a.Length, b.Length, "#1");
+                       Assert.AreEqual (a [0], b [0], "#2");
+               }
+
+               public Stream GetSerializedStream ()
+               {
+                       SerializationTest test = new SerializationTest (true, Int32.MinValue);
+                       BinaryFormatter bf = new BinaryFormatter ();
+                       MemoryStream ms = new MemoryStream ();
+                       bf.Serialize (ms, test);
+                       ms.Position = 0;
+                       return ms;
+               }
+
+               [Test]
+               public void QualifiedField()
+               {
+                       QualifiedFieldTest a = new QualifiedFieldTest ();
+                       a.ValueA = 1;
+                       a.ValueB = 2;
+                       a.Value = 3;
+                       Stream ms = new MemoryStream ();
+                       BinaryFormatter bf = new BinaryFormatter ();
+                       bf.Serialize(ms, a);
+                       ms.Position = 0;
+                       QualifiedFieldTest b = (QualifiedFieldTest)bf.Deserialize (ms);
+                       Assert.AreEqual (a.ValueA, b.ValueA, "#1");
+                       Assert.AreEqual (a.ValueB, b.ValueB, "#2");
+                       Assert.AreEqual (a.Value, b.Value, "#3");
+               }
+
+#if NET_4_0
+               [Test]
+               public void SerializationBindToName ()
+               {
+                       BinaryFormatter bf = new BinaryFormatter ();
+                       bf.AssemblyFormat = FormatterAssemblyStyle.Full;
+                       bf.Binder = new SimpleSerializationBinder ();
+                       MemoryStream ms = new MemoryStream ();
+
+                       SimpleSerializableObject o = new SimpleSerializableObject ();
+                       o.Name = "MonoObject";
+                       o.Id = 666;
+
+                       bf.Serialize (ms, o);
+                       ms.Position = 0;
+
+                       o = (SimpleSerializableObject)bf.Deserialize (ms);
+                       Assert.AreEqual ("MonoObject", o.Name);
+                       Assert.AreEqual (666, o.Id);
+               }
+
+               class SimpleSerializationBinder : SerializationBinder
+               {
+                       public override Type BindToType (string assemblyName, string typeName)
+                       {
+                               // We *should* be getting a SimpleSerializableObject2 instance
+                               // Otherwise it means we are not getting called our BindToName method.
+                               if (!typeName.EndsWith ("SimpleSerializableObject2"))
+                                       Assert.Fail ("#BindToType-TypeName");
+
+                               // We are also supposed to be getting a 9.9.9.9 version here,
+                               // and if we get a different version, it likely means BindToName was called.
+                               AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
+                               aname.Version = new Version (9, 9, 9, 9);
+                               if (aname.ToString () != assemblyName)
+                                       Assert.Fail ("#BindToType-AssemblyName");
+
+                               // No need to call Type.GetType
+                               return typeof (SimpleSerializableObject);
+                       }
+
+                       public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
+                       {
+                               AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
+                               aname.Version = new Version (9, 9, 9, 9);
+
+                               // Serialize mapping to this same assembly with 9.9.9.9 version
+                               // and a different type name.
+                               assemblyName = aname.ToString ();
+                               typeName = serializedType.FullName.Replace ("SimpleSerializableObject", "SimpleSerializableObject2");
+                       }
+               }
+
+               [Serializable]
+               class SimpleSerializableObject
+               {
+                       public string Name { get; set; }
+                       public int Id { get; set; }
+               }
+
+               [Test]
+               public void SerializationBindToName2 ()
+               {
+                       BinaryFormatter bf = new BinaryFormatter ();
+                       bf.AssemblyFormat = FormatterAssemblyStyle.Full;
+                       bf.Binder = new SimpleSerializationBinder2 ();
+                       MemoryStream ms = new MemoryStream ();
+
+                       SimpleISerializableObject o = new SimpleISerializableObject ();
+                       o.Name = "MonoObject";
+                       o.Id = 666;
+
+                       bf.Serialize (ms, o);
+                       ms.Position = 0;
+
+                       o = (SimpleISerializableObject)bf.Deserialize (ms);
+                       Assert.AreEqual ("MonoObject", o.Name);
+                       Assert.AreEqual (666, o.Id);
+
+                       ms.Close ();
+               }
+
+               [Test]
+               public void NestedObjectReferences ()
+               {
+                       MemoryStream ms = new MemoryStream ();
+
+                       var cls = new Class { Name = "MyClass" };
+                       var ob = cls.NewInstance ();
+
+                       BinaryFormatter bf = new BinaryFormatter();
+                       bf.Serialize (ms, new DynamicProxy (ob));
+
+                       ms.Position = 0;
+
+                       Instance ins = (Instance) bf.Deserialize (ms);
+                       Assert.AreEqual ("MyClass", ins.Class.Name);
+               }
+
+               class SimpleSerializationBinder2 : SerializationBinder
+               {
+                       public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
+                       {
+                               AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
+                               aname.Version = new Version (9, 9, 9, 9);
+
+                               // Serialize mapping to this same assembly with 9.9.9.9 version
+                               // and a different type name.
+                               assemblyName = aname.ToString ();
+                               typeName = serializedType.FullName.Replace ("SimpleISerializableObject", "SimpleISerializableObject2");
+                       }
+
+                       public override Type BindToType (string assemblyName, string typeName)
+                       {
+                               // We *should* be getting a SimpleISerializableObject2 instance
+                               if (!typeName.EndsWith ("SimpleISerializableObject2"))
+                                       Assert.Fail ("#BindToType-TypeName");
+
+                               // We are also supposed to be getting a 9.9.9.9 version here,
+                               // and if we get a different version, it likely means BindToName was called.
+                               AssemblyName aname = Assembly.GetExecutingAssembly ().GetName ();
+                               aname.Version = new Version (9, 9, 9, 9);
+                               if (aname.ToString () != assemblyName)
+                                       Assert.Fail ("#BindToType-AssemblyName");
+
+                               return typeof (SimpleISerializableObject);
+                       }
+               }
+
+               [Serializable]
+               class SimpleISerializableObject : ISerializable
+               {
+                       public string Name { get; set; }
+                       public int Id { get; set; }
+
+                       public SimpleISerializableObject ()
+                       {
+                       }
+
+                       protected SimpleISerializableObject (SerializationInfo info, StreamingContext context)
+                       {
+                               Name = info.GetString ("Name");
+                               Id = info.GetInt32 ("Id");
+                       }
+
+                       public void GetObjectData (SerializationInfo info, StreamingContext context)
+                       {
+                               info.AddValue ("Name", Name);
+                               info.AddValue ("Id", Id);
+                       }
+               }
+
+               [Serializable]
+               public class OtherClass
+               {
+               }
+
+               [Serializable]
+               public class BaseClass
+               {
+                       public OtherClass Other { get; set; }
+               }
+
+               public class CustomSerBinder: SerializationBinder
+               {
+                       public override void BindToName (Type serializedType, out string assemblyName, out string typeName)
+                       {
+                               assemblyName = null;
+                               if (serializedType == typeof (BaseClass))
+                                       typeName = "base";
+                               else if (serializedType == typeof (OtherClass))
+                                       typeName = "other";
+                               else
+                                       throw new ArgumentException ("Unknown type", "serializedType");
+                       }
+
+                       public override Type BindToType (string assemblyName, string typeName)
+                       {
+                               switch (typeName) {
+                               case "base":
+                                       return typeof (BaseClass);
+                               case "other":
+                                       return typeof (OtherClass);
+                               default:
+                                       throw new ArgumentException ("Unknown type name", "typeName");
+                               }
+                       }
+               }
+
+               [Test]
+               public void BinderShouldBeUsedForProperties ()
+               {
+                       using (var serStream = new MemoryStream ()) {
+                               var binder = new CustomSerBinder ();
+
+                               // serialize
+                               var original = new BaseClass () {
+                                       Other = new OtherClass ()
+                               };
+                               var formatter = new BinaryFormatter ();
+                               formatter.Binder = binder;
+                               formatter.Serialize (serStream, original);
+
+                               // deserialize, making sure we're using a new formatter, just to be thorough
+                               formatter = new BinaryFormatter ();
+                               formatter.Binder = binder;
+                               serStream.Seek (0, SeekOrigin.Begin);
+                               var deserialized = formatter.Deserialize (serStream);
+
+                               Assert.AreEqual (original.GetType (), deserialized.GetType ());
+                               Assert.AreEqual (original.Other.GetType (), ((BaseClass)deserialized).Other.GetType ());
+                       }
+               }
+#endif
        }
 }