using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using JetBrains.Collections.Viewable; using JetBrains.Core; using JetBrains.Rd; using JetBrains.Rd.Impl; using JetBrains.Rd.Reflection; using JetBrains.Serialization; using NUnit.Framework; using static JetBrains.Rd.Reflection.BuiltInSerializers.BuiltInType; namespace Test.RdFramework.Reflection { [TestFixture] public class ScalarBuiltInSerializerTests : RdReflectionTestBase { [Test] public void TestAllMarkedBuiltInTypes() { var additionalTypes = new Dictionary { { typeof(RdMap), ProtocolCollectionLike2 }, { typeof(RdList), ProtocolCollectionLike1 } }; foreach (var type in typeof(ScalarBuiltInSerializerTests).Assembly.GetTypes().Concat(additionalTypes.Keys)) { var expectedType = type.GetCustomAttribute()?.BuiltInType; if (additionalTypes.TryGetValue(type, out var knowType)) expectedType = knowType; if (expectedType.HasValue) { var builtInType = BuiltInSerializers.GetBuiltInType(type.GetTypeInfo()); if (builtInType != expectedType) { Assert.AreEqual(expectedType, builtInType, "Unexpected built-in serializer type detected for type {0}", type); } } } } [Test] public void TestReadWriteMethods() { WithExts((c, s) => { c.Simple.Value = new NoRedBuiltIn1(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [Test] public void TestReadWriteFields() { WithExts((c, s) => { c.Simple.Value = new NoRedBuiltIn2(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [Test] public void TestRdScalarAttribute() { WithExts((c, s) => { c.Simple.Value = new NoRedBuiltIn3(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [Test] public void TestRdSimpleMethods() { WithExts((c, s) => { c.Simple.Value = new NoRedBuiltIn4(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [Test] public void TestRdSimpleMethodsStaticWrite() { WithExts((c, s) => { c.Simple.Value = new OuterClass.NoRedBuiltIn5(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [Test] public void TestExternalSerialization() { void Reg(ReflectionSerializers cache) { cache.Register( (ctx, reader) => new ScalarTests.ColorFields(0, reader.ReadByte(), reader.ReadByte()), (ctx, writer, value) => { writer.WriteByte((byte) value.Green); writer.WriteByte((byte) value.Blue); }); } Reg(CFacade.Serializers); Reg(SFacade.Serializers); WithExts((c, s) => { c.Simple.Value = new ScalarTests.ColorFields(1,1,1); Assert.AreEqual(0, s.Simple.Value.Red); Assert.AreEqual(1, s.Simple.Value.Green); Assert.AreEqual(1, s.Simple.Value.Blue); }); } [RdExt] public class Ext1 : RdExtReflectionBindableBase { public IViewableProperty Simple { get; } } [RdExt] public class Ext2 : RdExtReflectionBindableBase { public IViewableProperty Simple { get; } } [RdExt] public class Ext3 : RdExtReflectionBindableBase { public IViewableProperty Simple { get; } } [RdExt] public class Ext4 : RdExtReflectionBindableBase { public IViewableProperty> Simple { get; } } [RdExt] public class Ext5 : RdExtReflectionBindableBase { public IViewableProperty.NoRedBuiltIn5> Simple { get; } } [RdExt] public class RegularExt : RdExtReflectionBindableBase { public IViewableProperty Simple { get; } } /// /// Built-in serializers way 1: special fields /// [RdScalar, AssertBuiltInType(StaticFields)] // not required public class NoRedBuiltIn1 { public int Red { get; } public int Green { get; } public int Blue { get; } public NoRedBuiltIn1(int red, int green, int blue) { Red = red; Green = green; Blue = blue; } public static CtxReadDelegate Read = (ctx, reader) => new NoRedBuiltIn1(0/*reader.ReadByte()*/, reader.ReadByte(), reader.ReadByte()); public static CtxWriteDelegate Write = (ctx, writer, value) => { // writer.Write((byte) value.Red); writer.WriteByte((byte) value.Green); writer.WriteByte((byte) value.Blue); }; } /// /// Built-in serializers way 2: magic static methods /// [RdScalar, AssertBuiltInType(StaticProtocolMethods)] // not required public class NoRedBuiltIn2 { public int Red { get; } public int Green { get; } public int Blue { get; } public NoRedBuiltIn2(int red, int green, int blue) { Red = red; Green = green; Blue = blue; } public static NoRedBuiltIn2 Read(SerializationCtx ctx, UnsafeReader reader) { return new NoRedBuiltIn2(0 /*reader.ReadByte()*/, reader.ReadByte(), reader.ReadByte()); } public static void Write(SerializationCtx ctx, UnsafeWriter writer, NoRedBuiltIn2 value) { // writer.Write((byte) value.Red); writer.WriteByte((byte) value.Green); writer.WriteByte((byte) value.Blue); } } /// /// Built-in serializers way 3: marshallers /// [RdScalar(typeof(Marshaller)), AssertBuiltInType(MarshallerAttribute)] public class NoRedBuiltIn3 { public int Red { get; } public int Green { get; } public int Blue { get; } public NoRedBuiltIn3(int red, int green, int blue) { Red = red; Green = green; Blue = blue; } } /// /// Built-in serializers way 4: implemented directly in type via Non-protocol methods with unsafe writers /// [AssertBuiltInType(Methods)] public class NoRedBuiltIn4 { public int Red { get; } public int Green { get; } public int Blue { get; } public NoRedBuiltIn4(int red, int green, int blue) { Red = red; Green = green; Blue = blue; } public static NoRedBuiltIn4 Read(UnsafeReader reader) { return new NoRedBuiltIn4(0 /*reader.ReadByte()*/, reader.ReadByte(), reader.ReadByte()); } public void Write(UnsafeWriter writer) { // writer.Write((byte) value.Red); writer.WriteByte((byte) Green); writer.WriteByte((byte) Blue); } // Overloads with same name are allowed public void Write(Stream stream) { } public static NoRedBuiltIn4 Read(Stream stream) => default; } public class OuterClass { /// /// Built-in serializers way 5: implemented directly in type via Non-protocol methods with unsafe writers, but write method can be static /// [AssertBuiltInType(StaticMethods)] public record NoRedBuiltIn5(int Red, int Green, int Blue) { public static NoRedBuiltIn5 Read(UnsafeReader reader) { return new NoRedBuiltIn5(0 /*reader.ReadByte()*/, reader.ReadByte(), reader.ReadByte()); } public static void Write(UnsafeWriter writer, NoRedBuiltIn5 value) { // writer.Write((byte) value.Red); writer.WriteByte((byte)value.Green); writer.WriteByte((byte)value.Blue); } public virtual bool Equals(NoRedBuiltIn5 other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Red == other.Red && Green == other.Green && Blue == other.Blue; } public override int GetHashCode() { unchecked { var hashCode = Red; hashCode = (hashCode * 397) ^ Green; hashCode = (hashCode * 397) ^ Blue; return hashCode; } } } } public class Marshaller : IBuiltInMarshaller { public NoRedBuiltIn3 Read(SerializationCtx ctx, UnsafeReader reader) { return new NoRedBuiltIn3(0 /*reader.ReadByte()*/, reader.ReadByte(), reader.ReadByte()); } public void Write(SerializationCtx ctx, UnsafeWriter writer, NoRedBuiltIn3 value) { // writer.Write((byte) value.Red); writer.WriteByte((byte) value.Green); writer.WriteByte((byte) value.Blue); } } } }