Skip to content

Commit

Permalink
Pre stage (#5)
Browse files Browse the repository at this point in the history
* - add support of IEnumerable with Add method (i.e. implementation enough for var x = new T() { e1, e2, e3 } syntax.
- add debug code

* - refactor the method of restoring IEnumerable with Add method (zachsaw#31)
- support of nullable in collections and as properties (zachsaw#34, zachsaw#35, zachsaw#36)

Co-authored-by: Nikolay Gekht <nikolay.gekht@gehtsoftusa.com>
  • Loading branch information
nikolaygekht and nikolaygekht committed Feb 12, 2021
1 parent b95a62f commit ebbf9cb
Show file tree
Hide file tree
Showing 8 changed files with 1,625 additions and 742 deletions.
39 changes: 39 additions & 0 deletions src/Binaron.Serializer.Tests/CustomTestCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Binaron.Serializer.Tests
{
public class CustomTestCollection<T> : IEnumerable<T>
{
private List<T> List = new List<T>();

public T this[int index] => List[index];

public int Count => List.Count;

public void Add(T value) => List.Add(value);


public IEnumerator<T> GetEnumerator() => List.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator();

public class TestCollectionObject
{
public T A { get; set; }

public TestCollectionObject()
{
}

public TestCollectionObject(T a)
{
A = a;
}
}
}
}
112 changes: 111 additions & 1 deletion src/Binaron.Serializer.Tests/ListSerializationTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -265,5 +265,115 @@ private static dynamic AddItem<TSourceItem>(Type sourceType, TSourceItem sourceI
throw new NotSupportedException();
}
}

[Test]
public void CustomCollectionIntTest()
{
CustomTestCollection<int> collection = new CustomTestCollection<int>()
{
0, 1, 2, 3, 4
};

var dest = Tester.TestRoundTrip<CustomTestCollection<int>>(collection);
Assert.AreEqual(5, dest.Count);
Assert.AreEqual(0, dest[0]);
Assert.AreEqual(1, dest[1]);
Assert.AreEqual(2, dest[2]);
Assert.AreEqual(3, dest[3]);
Assert.AreEqual(4, dest[4]);
}

[TestCaseSource(typeof(AllTestCases), nameof(AllTestCases.TestCaseOfValues))]
public void CustomCollectionOfTypeTest<TSource>(TSource v)
{
CustomTestCollection<TSource> collection = new CustomTestCollection<TSource>()
{
v
};

var dest = Tester.TestRoundTrip<CustomTestCollection<TSource>>(collection);
Assert.AreEqual(1, dest.Count);
Assert.AreEqual(v, dest[0]);
}


[Test]
public void CustomCollectionObjectTest()
{
CustomTestCollection<CustomTestCollection<int>.TestCollectionObject> collection = new CustomTestCollection<CustomTestCollection<int>.TestCollectionObject>()
{
new CustomTestCollection<int>.TestCollectionObject(0),
new CustomTestCollection<int>.TestCollectionObject(1),
new CustomTestCollection<int>.TestCollectionObject(2),
new CustomTestCollection<int>.TestCollectionObject(3),
new CustomTestCollection<int>.TestCollectionObject(4),
};

var dest = Tester.TestRoundTrip(collection);
Assert.AreEqual(5, dest.Count);
Assert.AreEqual(0, dest[0].A);
Assert.AreEqual(1, dest[1].A);
Assert.AreEqual(2, dest[2].A);
Assert.AreEqual(3, dest[3].A);
Assert.AreEqual(4, dest[4].A);
}

[Test]
public void TestListWithNullInside()
{
CustomTestCollection<CustomTestCollection<int>.TestCollectionObject> collection = new CustomTestCollection<CustomTestCollection<int>.TestCollectionObject>()
{
new CustomTestCollection<int>.TestCollectionObject(0),
new CustomTestCollection<int>.TestCollectionObject(1),
null,
new CustomTestCollection<int>.TestCollectionObject(3),
new CustomTestCollection<int>.TestCollectionObject(4),
};

var dest = Tester.TestRoundTrip(collection);
Assert.AreEqual(5, dest.Count);
Assert.AreEqual(0, dest[0].A);
Assert.AreEqual(1, dest[1].A);
Assert.AreEqual(null, dest[2]);
Assert.AreEqual(3, dest[3].A);
Assert.AreEqual(4, dest[4].A);
}

[Test]
public void TestListOfNullables1()
{
var collection = new CustomTestCollection<int?>() { 1, null, 2 };
using (var ms1 = new MemoryStream())
{
var so = new SerializerOptions();
BinaronConvert.Serialize(collection, ms1, so);
using (var ms2 = new MemoryStream(ms1.ToArray()))
{
var cr2 = BinaronConvert.Deserialize<CustomTestCollection<int?>>(ms2);
Assert.AreEqual(3, cr2.Count);
Assert.AreEqual(1, cr2[0]);
Assert.AreEqual(null, cr2[1]);
Assert.AreEqual(2, cr2[2]);
}
}
}
[Test]
public void TestListOfNullables2()
{
var collection = new List<int?>() { 1, null, 2 };
using (var ms1 = new MemoryStream())
{
var so = new SerializerOptions();
BinaronConvert.Serialize(collection, ms1, so);
using (var ms2 = new MemoryStream(ms1.ToArray()))
{
var cr2 = BinaronConvert.Deserialize<List<int?>>(ms2);
Assert.AreEqual(3, cr2.Count);
Assert.AreEqual(1, cr2[0]);
Assert.AreEqual(null, cr2[1]);
Assert.AreEqual(2, cr2[2]);
}
}
}
}
}
1 change: 1 addition & 0 deletions src/Binaron.Serializer.Tests/MemberGetSetterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ public int NoRead
set { }
}
}

}
}
62 changes: 62 additions & 0 deletions src/Binaron.Serializer.Tests/ValueSerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,68 @@ private static object GetEnumNumeric(object source)
}
}

[TestCase(1)]
[TestCase(null)]
public void NullableTest1(int? value)
{
using (var ms1 = new MemoryStream())
{
BinaronConvert.Serialize<int?>(value, ms1);
using (var ms2 = new MemoryStream(ms1.ToArray()))
{
Assert.AreEqual(value, BinaronConvert.Deserialize<int?>(ms2));

}
}
}

[TestCase(1, "a")]
[TestCase(null, null)]
[TestCase(1, null)]
[TestCase(null, "abcd")]

public void MemberSetterNullableType1(int? v1, string v2)
{
TestClass1 tc1 = new TestClass1() { IntValue = v1, StringValue = v2 };
using (MemoryStream ms = new MemoryStream())
{
BinaronConvert.Serialize(tc1, ms);
using (MemoryStream ms1 = new MemoryStream(ms.ToArray()))
{
var tc2 = BinaronConvert.Deserialize<TestClass1>(ms1);
Assert.AreEqual(v1, tc2.IntValue);
Assert.AreEqual(v2, tc2.StringValue);
}
}
}

[TestCase(1, "a")]
[TestCase(null, null)]
[TestCase(1, null)]
[TestCase(null, "abcd")]

public void MemberSetterNullableType2(int? v1, string v2)
{
List<TestClass1> tc1 = new List<TestClass1>() { new TestClass1() { IntValue = v1, StringValue = v2 } };
using (MemoryStream ms = new MemoryStream())
{
BinaronConvert.Serialize(tc1, ms);
using (MemoryStream ms1 = new MemoryStream(ms.ToArray()))
{
var tc2 = BinaronConvert.Deserialize<List<TestClass1>>(ms1);
Assert.AreEqual(1, tc2.Count);
Assert.AreEqual(v1, tc2[0].IntValue);
Assert.AreEqual(v2, tc2[0].StringValue);
}
}
}

private class TestClass1
{
public int? IntValue { get; set; }
public string StringValue { get; set; }
}

private class TestClass<T>
{
public DateTime RootValue { get; set; }
Expand Down
48 changes: 48 additions & 0 deletions src/Binaron.Serializer/Infrastructure/EnumerableWrapperWithAdd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;

namespace Binaron.Serializer.Infrastructure
{
internal class EnumerableWrapperWithAdd<T>
{
private readonly Action<object, T> Action;
private readonly object Result;
public bool HasAddAction { get; private set; } = false;

public EnumerableWrapperWithAdd(IEnumerable<T> result)
{
Result = result;
var method = result.GetType().GetMethod("Add", new Type[] { typeof(T) });

if (method == null)
Action = (o, v) => { };
else
{
HasAddAction = true;
DynamicMethod action = new DynamicMethod(
"Add",
null,
new Type[] { typeof(object), typeof(T) },
this.GetType().Module);

var il = action.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method);
il.Emit(OpCodes.Ret);

Action = (Action<object, T>)action.CreateDelegate(typeof(Action<object, T>));
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T value)
{
Action(Result, value);
}
}
}
Loading

0 comments on commit ebbf9cb

Please sign in to comment.