Skip to content

Commit d912cf1

Browse files
authored
Merge pull request #30 from IvanMurzak/fix/array-reflection-convertor
Fix serialization priority and improve deserialization in ArrayReflectionConvertor
2 parents 5971dc1 + 908b5e4 commit d912cf1

5 files changed

Lines changed: 462 additions & 101 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using Xunit;
3+
using Xunit.Abstractions;
4+
using com.IvanMurzak.ReflectorNet.Utils;
5+
6+
namespace com.IvanMurzak.ReflectorNet.Tests.Utils
7+
{
8+
public class ListSerializationTests : BaseTest
9+
{
10+
public ListSerializationTests(ITestOutputHelper output) : base(output) { }
11+
12+
public class ClassWithList
13+
{
14+
public List<int>? IntList { get; set; }
15+
}
16+
17+
[Fact]
18+
public void TestListDeserialization()
19+
{
20+
var original = new ClassWithList { IntList = new List<int> { 1, 2, 3 } };
21+
var reflector = new Reflector();
22+
var serialized = reflector.Serialize(original);
23+
var deserialized = reflector.Deserialize<ClassWithList>(serialized);
24+
25+
Assert.NotNull(deserialized);
26+
Assert.NotNull(deserialized.IntList);
27+
Assert.Equal(original.IntList.Count, deserialized.IntList.Count);
28+
Assert.Equal(original.IntList[0], deserialized.IntList[0]);
29+
}
30+
}
31+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Collections.Generic;
2+
using System.Text.Json;
3+
using Xunit;
4+
using Xunit.Abstractions;
5+
using com.IvanMurzak.ReflectorNet.Model;
6+
using com.IvanMurzak.ReflectorNet.Utils;
7+
8+
namespace com.IvanMurzak.ReflectorNet.Tests.Utils
9+
{
10+
public class PlainJsonArrayTest : BaseTest
11+
{
12+
public PlainJsonArrayTest(ITestOutputHelper output) : base(output) { }
13+
14+
[Fact]
15+
public void TestPlainJsonArrayDeserialization()
16+
{
17+
var json = "[1, 2, 3]";
18+
using var doc = JsonDocument.Parse(json);
19+
var root = doc.RootElement;
20+
21+
var serializedMember = new SerializedMember
22+
{
23+
typeName = "System.Collections.Generic.List`1[[System.Int32]]",
24+
valueJsonElement = root
25+
};
26+
27+
var reflector = new Reflector();
28+
var result = reflector.Deserialize<List<int>>(serializedMember);
29+
30+
Assert.NotNull(result);
31+
Assert.Equal(3, result.Count);
32+
Assert.Equal(1, result[0]);
33+
Assert.Equal(2, result[1]);
34+
Assert.Equal(3, result[2]);
35+
}
36+
37+
[Fact]
38+
public void TestSerializedMemberArrayDeserialization()
39+
{
40+
// Construct a JSON that looks like what Reflector produces
41+
// Array of SerializedMember objects
42+
var json = @"[
43+
{ ""typeName"": ""System.Int32"", ""value"": 1 },
44+
{ ""typeName"": ""System.Int32"", ""value"": 2 }
45+
]";
46+
using var doc = JsonDocument.Parse(json);
47+
var root = doc.RootElement;
48+
49+
var serializedMember = new SerializedMember
50+
{
51+
typeName = "System.Collections.Generic.List`1[[System.Int32]]",
52+
valueJsonElement = root
53+
};
54+
55+
var reflector = new Reflector();
56+
var result = reflector.Deserialize<List<int>>(serializedMember);
57+
58+
Assert.NotNull(result);
59+
Assert.Equal(2, result.Count);
60+
Assert.Equal(1, result[0]);
61+
Assert.Equal(2, result[1]);
62+
}
63+
}
64+
}
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xunit;
4+
using Xunit.Abstractions;
5+
using com.IvanMurzak.ReflectorNet.Utils;
6+
using com.IvanMurzak.ReflectorNet.Model;
7+
8+
namespace com.IvanMurzak.ReflectorNet.Tests.Utils
9+
{
10+
/// <summary>
11+
/// Tests to verify that deserialized lists maintain proper generic type information
12+
/// and are not incorrectly deserialized as List&lt;object?&gt;
13+
/// </summary>
14+
public class TypedListDeserializationTests : BaseTest
15+
{
16+
public TypedListDeserializationTests(ITestOutputHelper output) : base(output) { }
17+
18+
public class ClassWithListProperty
19+
{
20+
public List<int>? Numbers { get; set; }
21+
public List<string>? Names { get; set; }
22+
}
23+
24+
[Fact]
25+
public void List_Int_ShouldDeserializeAsTypedList()
26+
{
27+
// Arrange
28+
var original = new List<int> { 1, 2, 3, 4, 5 };
29+
var reflector = new Reflector();
30+
31+
// Act
32+
var serialized = reflector.Serialize(original);
33+
var deserialized = reflector.Deserialize(serialized);
34+
35+
// Assert
36+
Assert.NotNull(deserialized);
37+
38+
// Critical: The deserialized object should be List<int>, not List<object?>
39+
Assert.IsType<List<int>>(deserialized);
40+
41+
var typedList = (List<int>)deserialized;
42+
Assert.Equal(original.Count, typedList.Count);
43+
Assert.Equal(original[0], typedList[0]);
44+
Assert.Equal(original[4], typedList[4]);
45+
}
46+
47+
[Fact]
48+
public void List_String_ShouldDeserializeAsTypedList()
49+
{
50+
// Arrange
51+
var original = new List<string> { "hello", "world", "test" };
52+
var reflector = new Reflector();
53+
54+
// Act
55+
var serialized = reflector.Serialize(original);
56+
var deserialized = reflector.Deserialize(serialized);
57+
58+
// Assert
59+
Assert.NotNull(deserialized);
60+
61+
// Critical: The deserialized object should be List<string>, not List<object?>
62+
Assert.IsType<List<string>>(deserialized);
63+
64+
var typedList = (List<string>)deserialized;
65+
Assert.Equal(original.Count, typedList.Count);
66+
Assert.Equal(original[0], typedList[0]);
67+
Assert.Equal(original[2], typedList[2]);
68+
}
69+
70+
[Fact]
71+
public void List_Double_ShouldDeserializeAsTypedList()
72+
{
73+
// Arrange
74+
var original = new List<double> { 1.5, 2.7, 3.14159 };
75+
var reflector = new Reflector();
76+
77+
// Act
78+
var serialized = reflector.Serialize(original);
79+
var deserialized = reflector.Deserialize(serialized);
80+
81+
// Assert
82+
Assert.NotNull(deserialized);
83+
84+
// Critical: The deserialized object should be List<double>, not List<object?>
85+
Assert.IsType<List<double>>(deserialized);
86+
87+
var typedList = (List<double>)deserialized;
88+
Assert.Equal(original.Count, typedList.Count);
89+
Assert.Equal(original[0], typedList[0]);
90+
Assert.Equal(original[2], typedList[2]);
91+
}
92+
93+
public class TestPerson
94+
{
95+
public string? Name { get; set; }
96+
public int Age { get; set; }
97+
}
98+
99+
[Fact]
100+
public void List_ComplexType_ShouldDeserializeAsTypedList()
101+
{
102+
// Arrange
103+
var original = new List<TestPerson>
104+
{
105+
new TestPerson { Name = "Alice", Age = 30 },
106+
new TestPerson { Name = "Bob", Age = 25 }
107+
};
108+
var reflector = new Reflector();
109+
110+
// Act
111+
var serialized = reflector.Serialize(original);
112+
var deserialized = reflector.Deserialize(serialized);
113+
114+
// Assert
115+
Assert.NotNull(deserialized);
116+
117+
// Critical: The deserialized object should be List<TestPerson>, not List<object?>
118+
Assert.IsType<List<TestPerson>>(deserialized);
119+
120+
var typedList = (List<TestPerson>)deserialized;
121+
Assert.Equal(original.Count, typedList.Count);
122+
Assert.Equal(original[0].Name, typedList[0].Name);
123+
Assert.Equal(original[1].Age, typedList[1].Age);
124+
}
125+
126+
[Fact]
127+
public void List_GenericType_ShouldMaintainTypeInformation()
128+
{
129+
// Arrange
130+
var original = new List<int> { 10, 20, 30 };
131+
var reflector = new Reflector();
132+
133+
// Act
134+
var serialized = reflector.Serialize(original);
135+
var deserialized = reflector.Deserialize(serialized);
136+
137+
// Assert
138+
Assert.NotNull(deserialized);
139+
140+
// Verify the runtime type has the correct generic argument
141+
var deserializedType = deserialized.GetType();
142+
Assert.True(deserializedType.IsGenericType);
143+
Assert.Equal(typeof(List<>), deserializedType.GetGenericTypeDefinition());
144+
145+
var genericArgs = deserializedType.GetGenericArguments();
146+
Assert.Single(genericArgs);
147+
Assert.Equal(typeof(int), genericArgs[0]);
148+
}
149+
150+
[Fact]
151+
public void NestedList_ShouldDeserializeAsTypedList()
152+
{
153+
// Arrange
154+
var original = new List<List<int>>
155+
{
156+
new List<int> { 1, 2, 3 },
157+
new List<int> { 4, 5, 6 }
158+
};
159+
var reflector = new Reflector();
160+
161+
// Act
162+
var serialized = reflector.Serialize(original);
163+
var deserialized = reflector.Deserialize(serialized);
164+
165+
// Assert
166+
Assert.NotNull(deserialized);
167+
168+
// Critical: The deserialized object should be List<List<int>>, not List<object?>
169+
Assert.IsType<List<List<int>>>(deserialized);
170+
171+
var typedList = (List<List<int>>)deserialized;
172+
Assert.Equal(original.Count, typedList.Count);
173+
Assert.Equal(original[0][0], typedList[0][0]);
174+
Assert.Equal(original[1][2], typedList[1][2]);
175+
}
176+
177+
[Fact]
178+
public void ClassWithListProperty_ShouldDeserializeListPropertyAsTypedList()
179+
{
180+
// Arrange
181+
var original = new ClassWithListProperty
182+
{
183+
Numbers = new List<int> { 10, 20, 30 },
184+
Names = new List<string> { "Alice", "Bob", "Charlie" }
185+
};
186+
var reflector = new Reflector();
187+
188+
// Act
189+
var serialized = reflector.Serialize(original);
190+
_output.WriteLine($"Serialized: {serialized.ToJson(reflector)}");
191+
192+
var deserialized = reflector.Deserialize<ClassWithListProperty>(serialized);
193+
194+
// Assert
195+
Assert.NotNull(deserialized);
196+
Assert.NotNull(deserialized.Numbers);
197+
Assert.NotNull(deserialized.Names);
198+
199+
// Critical: The deserialized properties should be List<int> and List<string>, not List<object?>
200+
Assert.IsType<List<int>>(deserialized.Numbers);
201+
Assert.IsType<List<string>>(deserialized.Names);
202+
203+
Assert.Equal(original.Numbers.Count, deserialized.Numbers.Count);
204+
Assert.Equal(original.Names.Count, deserialized.Names.Count);
205+
Assert.Equal(original.Numbers[0], deserialized.Numbers[0]);
206+
Assert.Equal(original.Names[0], deserialized.Names[0]);
207+
}
208+
209+
[Fact]
210+
public void DirectListDeserializationViaSerializedMember_ShouldBeTyped()
211+
{
212+
// This test directly exercises TryDeserializeValueListInternal
213+
// by creating a SerializedMember with a JSON array
214+
215+
var reflector = new Reflector();
216+
217+
// Create a serialized member representing a List<int> with JSON array
218+
var jsonArray = System.Text.Json.JsonSerializer.SerializeToElement(new[] { 1, 2, 3, 4, 5 });
219+
var serializedMember = new SerializedMember
220+
{
221+
typeName = "System.Collections.Generic.List`1[[System.Int32]]",
222+
valueJsonElement = jsonArray
223+
};
224+
225+
// Act
226+
var deserialized = reflector.Deserialize(serializedMember);
227+
228+
// Assert
229+
Assert.NotNull(deserialized);
230+
_output.WriteLine($"Deserialized type: {deserialized.GetType().FullName}");
231+
232+
// Critical: Should be List<int>, not List<object?>
233+
Assert.IsType<List<int>>(deserialized);
234+
235+
var typedList = (List<int>)deserialized;
236+
Assert.Equal(5, typedList.Count);
237+
Assert.Equal(1, typedList[0]);
238+
Assert.Equal(5, typedList[4]);
239+
}
240+
}
241+
}

0 commit comments

Comments
 (0)