Files
simulation_core/lib/Migrant/Tests/SurrogateTests.cs

439 lines
14 KiB
C#

//
// Copyright (c) 2012-2021 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in the LICENSE file.
using System;
using NUnit.Framework;
using System.IO;
using Antmicro.Migrant;
using System.Collections.Generic;
using System.Reflection;
namespace Antmicro.Migrant.Tests
{
[TestFixture(false, false, true)]
[TestFixture(true, false, true)]
[TestFixture(false, true, true)]
[TestFixture(true, true, true)]
[TestFixture(false, false, false)]
[TestFixture(true, false, false)]
[TestFixture(false, true, false)]
[TestFixture(true, true, false)]
public class SurrogateTests : BaseTestWithSettings
{
public SurrogateTests(bool useGeneratedSerializer, bool useGeneratedDeserializer, bool useTypeStamping) : base(useGeneratedSerializer, useGeneratedDeserializer, false, false, false, useTypeStamping, true)
{
}
[Test]
public void ShouldPlaceObjectForSurrogate()
{
var b = new SurrogateMockB();
var pseudocopy = PseudoClone(b, serializer =>
{
serializer.ForSurrogate<SurrogateMockB>().SetObject(x => new SurrogateMockA(999));
});
var a = pseudocopy as SurrogateMockA;
Assert.IsNotNull(a);
Assert.AreEqual(999, a.Field);
}
[Test]
public void ShouldPlaceObjectForSurrogatePreservingIdentity()
{
var b = new SurrogateMockB();
var list = new List<object> { b, new List<object> { b }, new SurrogateMockB() };
var counter = 0;
var pseudocopy = PseudoClone(list, serializer =>
{
serializer.ForSurrogate<SurrogateMockB>().SetObject(x => new SurrogateMockA(counter++));
});
list = pseudocopy as List<object>;
Assert.IsNotNull(list);
var sublist = list[1] as List<object>;
Assert.IsNotNull(sublist);
Assert.AreSame(list[0], sublist[0]);
Assert.AreNotSame(list[0], list[2]);
var a = list[0] as SurrogateMockA;
Assert.IsNotNull(a);
Assert.AreEqual(3, a.Field);
var secondA = list[2] as SurrogateMockA;
Assert.IsNotNull(secondA);
Assert.AreEqual(2, secondA.Field);
}
[Test]
public void ShouldPlaceSurrogateForObject()
{
var b = new SurrogateMockB();
var pseudocopy = PseudoClone(b, serializer =>
{
serializer.ForObject<SurrogateMockB>().SetSurrogate(x => new SurrogateMockA(1));
});
var a = pseudocopy as SurrogateMockA;
Assert.IsNotNull(a);
Assert.AreEqual(1, a.Field);
}
[Test]
public void ShouldPlaceSurrogateForObjectPreservingIdentity()
{
var b = new SurrogateMockB();
var counter = 0;
var list = new List<object> { b, new SurrogateMockB(), b };
var pseudocopy = PseudoClone(list, serializer =>
{
serializer.ForObject<SurrogateMockB>().SetSurrogate(x => new SurrogateMockA(counter++));
});
list = pseudocopy as List<object>;
Assert.IsNotNull(list);
Assert.AreSame(list[0], list[2]);
Assert.AreNotSame(list[0], list[1]);
var a = list[0] as SurrogateMockA;
Assert.IsNotNull(a);
Assert.AreEqual(counter - 2, a.Field);
var secondA = list[1] as SurrogateMockA;
Assert.IsNotNull(secondA);
Assert.AreEqual(counter - 1, secondA.Field);
}
[Test]
public void ShouldAllowBoxedValueTypeSurrogation()
{
int a = 199;
var pseudocopy = PseudoClone(a, serializer =>
{
serializer.ForObject<int>().SetSurrogate(x => new IntSurrogate(x));
serializer.ForSurrogate<IntSurrogate>().SetObject(x => (object)(x.cwi.field));
});
var b = pseudocopy as object;
Assert.AreEqual(299, b);
}
private class ClassWithInteger
{
public int field;
}
private class IntSurrogate
{
public IntSurrogate(int value)
{
cwi = new ClassWithInteger { field = value + 100 };
}
public ClassWithInteger cwi;
}
[Test]
public void ShouldDoSurrogateObjectSwap()
{
var b = new SurrogateMockB();
var pseudocopy = PseudoClone(b, serializer =>
{
serializer.ForObject<SurrogateMockB>().SetSurrogate(x => new SurrogateMockA(1));
serializer.ForSurrogate<SurrogateMockA>().SetObject(x => new SurrogateMockC());
});
var c = pseudocopy as SurrogateMockC;
Assert.IsNotNull(c);
}
[Test]
public void ShouldPlaceObjectForDerivedSurrogate()
{
var d = new SurrogateMockD();
var pseudocopy = PseudoClone(d, serializer =>
{
serializer.ForSurrogate<SurrogateMockC>().SetObject(x => new SurrogateMockB());
});
var b = pseudocopy as SurrogateMockB;
Assert.IsNotNull(b);
}
[Test]
public void ShouldPlaceSurrogateForDerivedObject()
{
var d = new SurrogateMockD();
var pseudocopy = PseudoClone(d, serializer =>
{
serializer.ForObject<SurrogateMockC>().SetSurrogate(x => new SurrogateMockB());
});
var b = pseudocopy as SurrogateMockB;
Assert.IsNotNull(b);
}
[Test]
public void ShouldPlaceObjectForSurrogateImplementingInterface()
{
var e = new SurrogateMockE();
var pseudocopy = PseudoClone(e, serializer =>
{
serializer.ForSurrogate<ISurrogateMockE>().SetObject(x => new SurrogateMockB());
});
var b = pseudocopy as SurrogateMockB;
Assert.IsNotNull(b);
}
[Test]
public void ShouldPlaceSurrogateForObjectImplementingInterface()
{
var e = new SurrogateMockE();
var pseudocopy = PseudoClone(e, serializer =>
{
serializer.ForObject<ISurrogateMockE>().SetSurrogate(x => new SurrogateMockB());
});
var b = pseudocopy as SurrogateMockB;
Assert.IsNotNull(b);
}
[Test]
public void ShouldUseMoreSpecificSurrogateIfPossible()
{
var mock = new SurrogateMockD();
var pseudocopy = PseudoClone(mock, serializer =>
{
serializer.ForObject<SurrogateMockC>().SetSurrogate(x => new SurrogateMockA(1));
serializer.ForObject<SurrogateMockD>().SetSurrogate(x => new SurrogateMockB());
});
var b = pseudocopy as SurrogateMockB;
Assert.IsNotNull(b);
}
[Test]
public void ShouldThrowWhenSettingSurrogatesAfterSerialization()
{
var serializer = new Serializer(GetSettings());
serializer.Serialize(new object(), Stream.Null);
Assert.Throws<InvalidOperationException>(() => serializer.ForObject<object>().SetSurrogate(x => new object()));
}
[Test]
public void ShouldThrowWhenSettingObjectForSurrogateAfterDeserialization()
{
var serializer = new Serializer(GetSettings());
var stream = new MemoryStream();
serializer.Serialize(new object(), stream);
stream.Seek(0, SeekOrigin.Begin);
serializer.Deserialize<object>(stream);
Assert.Throws<InvalidOperationException>(() => serializer.ForSurrogate<object>().SetObject(x => new object()));
}
[Test]
public void ShouldDoSurrogateObjectSwapTwoTimes()
{
var b = new SurrogateMockB();
var serializer = new Serializer(GetSettings());
serializer.ForObject<SurrogateMockB>().SetSurrogate(x => new SurrogateMockA(1));
serializer.ForSurrogate<SurrogateMockA>().SetObject(x => new SurrogateMockC());
for(var i = 0; i < 2; i++)
{
using(var stream = new MemoryStream())
{
serializer.Serialize(b, stream);
stream.Seek(0, SeekOrigin.Begin);
var pseudocopy = serializer.Deserialize<object>(stream);
var c = pseudocopy as SurrogateMockC;
Assert.IsNotNull(c);
}
}
}
[Test]
public void ShouldUseSurrogateAddedFirstWhenBothMatch()
{
var h = new SurrogateMockH();
var pseudocopy = PseudoClone(h, serializer =>
{
serializer.ForObject<ISurrogateMockG>().SetSurrogate(x => "g");
serializer.ForObject<ISurrogateMockE>().SetSurrogate(x => "e");
});
Assert.AreEqual("g", pseudocopy);
}
[Test]
public void ShouldSwapGenericSurrogateWithObject()
{
var f = new SurrogateMockF<string>("test");
var pseudocopy = PseudoClone(f, serializer => serializer.ForObject(typeof(SurrogateMockF<>)).SetSurrogate(x =>
{
var type = x.GetType();
return type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)[0].GetValue(x);
}));
Assert.IsInstanceOf<string>(pseudocopy);
}
[Test]
public void ShouldSwapWithNonGenericSurrogate()
{
var f = new SurrogateMockF<string>("test");
var pseudocopy = PseudoClone(f, serializer =>
{
serializer.ForObject(typeof(SurrogateMockF<>)).SetSurrogate(x => "general");
serializer.ForObject<SurrogateMockF<string>>().SetSurrogate(x => "special");
});
Assert.AreEqual("special", pseudocopy);
}
[Test]
public void ShouldUseGenericBaseSurrogateForDerivedClass()
{
var i = new SurrogateMockI<string>("something");
var pseudocopy = PseudoClone(i, serializer =>
serializer.ForObject(typeof(SurrogateMockF<>)).SetSurrogate(x => "success"));
Assert.AreEqual("success", pseudocopy);
}
[Test]
public void ShouldUseMoreSpecificGenericSurrogateIfPossible()
{
var i = new SurrogateMockI<string>("something");
var pseudocopy = PseudoClone(i, serializer =>
{
serializer.ForObject(typeof(SurrogateMockF<>)).SetSurrogate(x => "fail");
serializer.ForObject(typeof(SurrogateMockI<>)).SetSurrogate(x => "success");
});
Assert.AreEqual("success", pseudocopy);
}
[Test]
public void ShouldTreatNullAsDontSurrogateThisType()
{
var d = new SurrogateMockD();
var pseudocopy = PseudoClone(d, serializer =>
{
serializer.ForObject(typeof(SurrogateMockC)).SetSurrogate(x => "fail");
serializer.ForObject(typeof(SurrogateMockD)).SetSurrogate(null);
});
Assert.IsInstanceOf<SurrogateMockD>(pseudocopy);
}
[Test]
public void ShouldDeserializeSurrogatePointingToItself()
{
var obj = new object();
var pseudocopy = PseudoClone(obj, serializer =>
{
serializer.ForSurrogate(typeof(object)).SetObject(x =>
{
var j = new SurrogateMockJ();
j.field = j;
return j;
});
});
Assert.IsInstanceOf<SurrogateMockJ>(pseudocopy);
Assert.AreEqual(pseudocopy, ((SurrogateMockJ)pseudocopy).field);
}
[Test]
public void ShouldNotGenerateGenericSurrogateTwice()
{
var d = new ClassWithGenericSurrogates();
Serializer serializerInstance = null;
int surrogatesBeforeSerialization = 0;
var pseudocopy = PseudoClone(d, serializer =>
{
serializer.ForObject(typeof(ClassToBeSurrogated<>)).SetSurrogateGenericType(typeof(SurrogatingClass<>));
serializerInstance = serializer;
surrogatesBeforeSerialization = serializer.surrogatesForObjects.Count;
});
Assert.IsInstanceOf<ClassWithGenericSurrogates>(pseudocopy);
Assert.IsInstanceOf<SurrogatingClass<int>>(((ClassWithGenericSurrogates)pseudocopy).fieldA);
Assert.IsInstanceOf<SurrogatingClass<float>>(((ClassWithGenericSurrogates)pseudocopy).fieldB);
Assert.IsInstanceOf<SurrogatingClass<int>>(((ClassWithGenericSurrogates)pseudocopy).fieldC);
Assert.AreEqual(useGeneratedSerializer ? 2 : 0, serializerInstance.surrogatesForObjects.Count - surrogatesBeforeSerialization);
}
private class ClassWithGenericSurrogates
{
internal object fieldA = new ClassToBeSurrogated<int>();
internal object fieldB = new ClassToBeSurrogated<float>();
internal object fieldC = new ClassToBeSurrogated<int>();
}
private class ClassToBeSurrogated<T>
{
}
private class SurrogatingClass<T>
{
public SurrogatingClass(ClassToBeSurrogated<T> x)
{
}
}
}
public class SurrogateMockA
{
public SurrogateMockA(int field)
{
Field = field;
}
public int Field { get; private set; }
}
public class SurrogateMockB
{
}
public class SurrogateMockC
{
}
public class SurrogateMockD : SurrogateMockC
{
}
public interface ISurrogateMockE
{
}
public class SurrogateMockE : ISurrogateMockE
{
}
public class SurrogateMockF<T>
{
public SurrogateMockF(T value)
{
Value = value;
}
public T Value { get; private set; }
}
public interface ISurrogateMockG
{
}
public class SurrogateMockH : ISurrogateMockE, ISurrogateMockG
{
}
public class SurrogateMockI<T> : SurrogateMockF<T>
{
public SurrogateMockI(T value) : base(value)
{
}
}
public class SurrogateMockJ
{
public SurrogateMockJ field;
}
}