Skip to content

Commit

Permalink
Test serialize with inheritance. Fix #15.
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanLarsson committed Sep 9, 2018
1 parent e064b51 commit 699c4bd
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 10 deletions.
61 changes: 61 additions & 0 deletions Gu.Xml.Tests/XmlTests.SerializeCollections.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace Gu.Xml.Tests
{
using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;

public partial class XmlTests
{
public class SerializeCollections
{
private static readonly TestCaseData[] Values =
{
new TestCaseData(new[] { 1, 2, 3 }),
new TestCaseData(new[] { new Foo(1), new Foo(2), new Foo(3) }),
new TestCaseData(new List<int> { 1, 2, 3 }),
new TestCaseData(new List<Foo> { new Foo(1), new Foo(2), new Foo(3) }),
new TestCaseData(new Dictionary<int, string> { { 1, "a" }, { 2, "b" } }),
new TestCaseData(new ArrayList { 1, 2, 3 }),
};

[TestCaseSource(nameof(Values))]
public void Serialize(object value)
{
var expected = Reference.Xml(value);
var actual = Xml.Serialize(value);
if (actual == expected)
{
return;
}

Console.WriteLine("Expected:");
Console.Write(expected);
Console.WriteLine();
Console.WriteLine();

Console.WriteLine("Actual:");
Console.Write(actual);
Console.WriteLine();
Console.WriteLine();

Assert.AreEqual(expected, actual);
}

public class Foo
{
// ReSharper disable once UnusedMember.Local for XmlSerializer
private Foo()
{
}

public Foo(int value)
{
this.Value = value;
}

public int Value { get; }
}
}
}
}
33 changes: 26 additions & 7 deletions Gu.Xml.Tests/XmlTests.SerializeComplextTypes.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
namespace Gu.Xml.Tests
#pragma warning disable SA1201 // Elements should appear in the correct order
namespace Gu.Xml.Tests
{
using System;
using System.Collections.Generic;
Expand All @@ -15,9 +16,11 @@ public class SerializeComplexTypes
new TestCaseData(new WithPublicMutableFieldXmlElementExplicitName { Value = 1 }),
new TestCaseData(new WithPublicMutableField { Value = 1 }),
new TestCaseData(new WithPublicMutableFieldXmlElementExplicitName { Value = 1 }),
new TestCaseData(new WithTwoPublicMutableProperties { Value1 = 1, Value2 = 1 }),
new TestCaseData(new WithFieldBeforeProperty { Value1 = 1, Value2 = 1 }),
new TestCaseData(new WithPropertyBeforeField { Value1 = 1, Value2 = 1 }),
new TestCaseData(new WithTwoPublicMutableProperties { Value1 = 1, Value2 = 2 }),
new TestCaseData(new WithFieldBeforeProperty { Value1 = 1, Value2 = 2 }),
new TestCaseData(new WithPropertyBeforeField { Value1 = 1, Value2 = 2 }),
new TestCaseData(new ConcreteWithProperties { Value1 = 1, Value2 = 2, Value3 = 3, Value4 = 4 }),
new TestCaseData(new ConcreteWithFields { Value1 = 1, Value2 = 2, Value3 = 3, Value4 = 4 }),
new TestCaseData(new Virtual { Value = 3 }),
new TestCaseData(new Override { Value = 3 }),
new TestCaseData(new GenericWithPublicMutableProperty<int> { Value = 1 }),
Expand Down Expand Up @@ -151,14 +154,30 @@ public StructWithGetOnlyProperty(int value)
public int Value { get; }
}

public abstract class Abstract
public abstract class AbstractWithProperty
{
public int Value1 { get; set; } = 1;

public int Value2 { get; set; } = 2;
}

public class Concrete : Abstract
public class ConcreteWithProperties : AbstractWithProperty
{
public int Value2 { get; set; } = 2;
public int Value3 { get; set; } = 3;

public int Value4 { get; set; } = 3;
}

public abstract class AbstractWithField
{
public int Value1 = 1;
public int Value2 = 2;
}

public class ConcreteWithFields : AbstractWithField
{
public int Value3 = 3;
public int Value4 = 4;
}

public class Virtual
Expand Down
60 changes: 57 additions & 3 deletions Gu.Xml/Writers/ComplexValueWriter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Gu.Xml
{
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -25,10 +26,17 @@ public static ComplexValueWriter GetOrCreate<T>(T value)
return Default.GetOrAdd(value.GetType(), x => Create(x));
}

private static ComplexValueWriter Create(Type type)
public static ComplexValueWriter Create(Type type)
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.FlattenHierarchy);
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy);
if (!type.IsValueType &&
type.BaseType != typeof(object))
{
Array.Sort(fields, BaseTypeCountComparer.Default);
Array.Sort(properties, BaseTypeCountComparer.Default);
}

return new ComplexValueWriter(
Attributes().ToArray(),
Elements().ToArray());
Expand Down Expand Up @@ -71,5 +79,51 @@ IEnumerable<ElementWriter> Elements()
}
}
}

private sealed class BaseTypeCountComparer : IComparer<Type>, IComparer<MemberInfo>, IComparer
{
public static readonly BaseTypeCountComparer Default = new BaseTypeCountComparer();

public int Compare(MemberInfo x, MemberInfo y) => this.Compare(x.DeclaringType, y.DeclaringType);

public int Compare(Type x, Type y)
{
if (x == y)
{
return 0;
}

return Count(x).CompareTo(Count(y));
}

int IComparer.Compare(object x, object y)
{
if (x is PropertyInfo xp &&
y is PropertyInfo yp)
{
return this.Compare(xp, yp);
}

if (x is Type xt &&
y is Type yt)
{
return this.Compare(xt, yt);
}

return 0;
}

private static int Count(Type type)
{
var count = 0;
while (type.BaseType != null)
{
count++;
type = type.BaseType;
}

return count;
}
}
}
}

0 comments on commit 699c4bd

Please sign in to comment.