Skip to content

Commit 46d88b1

Browse files
committed
test: add comprehensive nested class JSON Schema coverage
- Add deeply nested (LevelOne.LevelTwo.LevelThree.LevelFour) test types - Add generic nested (GenericOuter<T>.GenericInner<U>) test types - Add type ID sanitization tests for +, <, > characters - Add schema generation tests for nested class / validation - Add return schema, argument schema, and array schema tests for nested types - Add cross-assembly nested class schema validation All 1438 tests pass (including 27 new ones).
1 parent 95f51f9 commit 46d88b1

3 files changed

Lines changed: 252 additions & 5 deletions

File tree

ReflectorNet.Tests.OuterAssembly/src/Model/NestedClass.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,35 @@ public WrapperClass(T? valueField, T? valueProperty)
6565
/// </summary>
6666
public T? EchoNullable(T? value) => value;
6767
}
68+
69+
public class LevelOne
70+
{
71+
public class LevelTwo
72+
{
73+
public class LevelThree
74+
{
75+
public class LevelFour
76+
{
77+
public string DeepProperty { get; set; } = "deep";
78+
}
79+
80+
public LevelFour? NestedInstance { get; set; }
81+
}
82+
83+
public LevelThree? NestedInstance { get; set; }
84+
}
85+
86+
public LevelTwo? NestedInstance { get; set; }
87+
}
88+
89+
public class GenericOuter<T>
90+
{
91+
public class GenericInner<U>
92+
{
93+
public T? OuterValue { get; set; }
94+
public U? InnerValue { get; set; }
95+
}
96+
97+
public GenericInner<T>? SelfReferencingInner { get; set; }
98+
}
6899
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using System.Text.Json.Nodes;
5+
using com.IvanMurzak.ReflectorNet.OuterAssembly.Model;
6+
using com.IvanMurzak.ReflectorNet.Utils;
7+
using Xunit.Abstractions;
8+
9+
namespace com.IvanMurzak.ReflectorNet.Tests.SchemaTests
10+
{
11+
public class NestedClassSchemaTests : SchemaTestBase
12+
{
13+
public NestedClassSchemaTests(ITestOutputHelper output) : base(output) { }
14+
15+
[Fact]
16+
public void Schema_NestedClass_GeneratesValidSchema()
17+
{
18+
var reflector = new Reflector();
19+
var schema = JsonSchemaValidation(typeof(ParentClass.NestedClass), reflector);
20+
21+
Assert.NotNull(schema);
22+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
23+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
24+
25+
var properties = schema[JsonSchema.Properties]!.AsObject();
26+
Assert.True(properties.ContainsKey("NestedField"));
27+
Assert.True(properties.ContainsKey("NestedProperty"));
28+
Assert.False(properties.ContainsKey("NestedStaticField"));
29+
Assert.False(properties.ContainsKey("NestedStaticProperty"));
30+
}
31+
32+
[Fact]
33+
public void Schema_DeeplyNestedClass_GeneratesValidSchema()
34+
{
35+
var reflector = new Reflector();
36+
var schema = JsonSchemaValidation(typeof(LevelOne.LevelTwo.LevelThree.LevelFour), reflector);
37+
38+
Assert.NotNull(schema);
39+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
40+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
41+
42+
var properties = schema[JsonSchema.Properties]!.AsObject();
43+
Assert.True(properties.ContainsKey("DeepProperty"));
44+
}
45+
46+
[Fact]
47+
public void Schema_DeeplyNestedHierarchy_GeneratesValidSchema()
48+
{
49+
var reflector = new Reflector();
50+
var schema = JsonSchemaValidation(typeof(LevelOne), reflector);
51+
52+
Assert.NotNull(schema);
53+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
54+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
55+
56+
var properties = schema[JsonSchema.Properties]!.AsObject();
57+
Assert.True(properties.ContainsKey("NestedInstance"));
58+
59+
var nestedInstanceSchema = properties["NestedInstance"]!.AsObject();
60+
Assert.True(nestedInstanceSchema.ContainsKey(JsonSchema.Ref) || nestedInstanceSchema.ContainsKey(JsonSchema.Type));
61+
62+
AssertAllRefsDefined(schema);
63+
}
64+
65+
[Fact]
66+
public void Schema_GenericNestedClass_GeneratesValidSchema()
67+
{
68+
var reflector = new Reflector();
69+
var type = typeof(GenericOuter<int>.GenericInner<string>);
70+
var schema = JsonSchemaValidation(type, reflector);
71+
72+
Assert.NotNull(schema);
73+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
74+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
75+
76+
var properties = schema[JsonSchema.Properties]!.AsObject();
77+
Assert.True(properties.ContainsKey("OuterValue"));
78+
Assert.True(properties.ContainsKey("InnerValue"));
79+
}
80+
81+
[Fact]
82+
public void Schema_GenericNestedClass_SelfReferencing_GeneratesValidSchema()
83+
{
84+
var reflector = new Reflector();
85+
var type = typeof(GenericOuter<int>);
86+
var schema = JsonSchemaValidation(type, reflector);
87+
88+
Assert.NotNull(schema);
89+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
90+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
91+
92+
var properties = schema[JsonSchema.Properties]!.AsObject();
93+
Assert.True(properties.ContainsKey("SelfReferencingInner"));
94+
95+
AssertAllRefsDefined(schema);
96+
}
97+
98+
[Fact]
99+
public void Schema_NestedClass_RefsAreDefinedInDefs()
100+
{
101+
var reflector = new Reflector();
102+
var type = typeof(LevelOne);
103+
var schema = reflector.GetSchema(type);
104+
105+
Assert.NotNull(schema);
106+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Defs), "Schema should contain $defs for nested types");
107+
108+
var defines = schema[JsonSchema.Defs]!.AsObject();
109+
Assert.NotNull(defines);
110+
111+
var levelTwoId = typeof(LevelOne.LevelTwo).GetSchemaTypeId();
112+
var levelThreeId = typeof(LevelOne.LevelTwo.LevelThree).GetSchemaTypeId();
113+
var levelFourId = typeof(LevelOne.LevelTwo.LevelThree.LevelFour).GetSchemaTypeId();
114+
115+
Assert.True(defines.ContainsKey(levelTwoId), $"$defs should contain {levelTwoId}");
116+
Assert.True(defines.ContainsKey(levelThreeId), $"$defs should contain {levelThreeId}");
117+
Assert.True(defines.ContainsKey(levelFourId), $"$defs should contain {levelFourId}");
118+
119+
AssertAllRefsDefined(schema);
120+
}
121+
122+
[Fact]
123+
public void Schema_NestedClass_ReturnSchema_HasValidRefs()
124+
{
125+
var reflector = new Reflector();
126+
var methodInfo = GetType().GetMethod(nameof(NestedClassReturnMethod), BindingFlags.NonPublic | BindingFlags.Instance)!;
127+
var schema = reflector.GetReturnSchema(methodInfo);
128+
129+
Assert.NotNull(schema);
130+
AssertCustomTypeReturnSchema(schema, new[] { "NestedField", "NestedProperty" }, shouldBeRequired: true);
131+
AssertAllRefsDefined(schema);
132+
}
133+
134+
[Fact]
135+
public void Schema_DeeplyNestedClass_ReturnSchema_HasValidRefs()
136+
{
137+
var reflector = new Reflector();
138+
var methodInfo = GetType().GetMethod(nameof(DeeplyNestedClassReturnMethod), BindingFlags.NonPublic | BindingFlags.Instance)!;
139+
var schema = reflector.GetReturnSchema(methodInfo);
140+
141+
Assert.NotNull(schema);
142+
AssertCustomTypeReturnSchema(schema, new[] { "DeepProperty" }, shouldBeRequired: true);
143+
AssertAllRefsDefined(schema);
144+
}
145+
146+
[Fact]
147+
public void Schema_GenericNestedClass_ReturnSchema_HasValidRefs()
148+
{
149+
var reflector = new Reflector();
150+
var methodInfo = GetType().GetMethod(nameof(GenericNestedClassReturnMethod), BindingFlags.NonPublic | BindingFlags.Instance)!;
151+
var schema = reflector.GetReturnSchema(methodInfo);
152+
153+
Assert.NotNull(schema);
154+
AssertCustomTypeReturnSchema(schema, new[] { "OuterValue", "InnerValue" }, shouldBeRequired: true);
155+
AssertAllRefsDefined(schema);
156+
}
157+
158+
[Fact]
159+
public void Schema_NestedClass_Array_ReturnSchema_HasValidRefs()
160+
{
161+
var reflector = new Reflector();
162+
var methodInfo = GetType().GetMethod(nameof(NestedClassArrayReturnMethod), BindingFlags.NonPublic | BindingFlags.Instance)!;
163+
var schema = reflector.GetReturnSchema(methodInfo);
164+
165+
Assert.NotNull(schema);
166+
AssertArrayReturnSchema(schema, JsonSchema.Object, shouldBeRequired: true);
167+
AssertAllRefsDefined(schema);
168+
}
169+
170+
[Fact]
171+
public void Schema_NestedClass_ArgumentSchema_HasValidRefs()
172+
{
173+
var reflector = new Reflector();
174+
var methodInfo = GetType().GetMethod(nameof(NestedClassArgumentMethod), BindingFlags.NonPublic | BindingFlags.Instance)!;
175+
var schema = reflector.GetArgumentsSchema(methodInfo);
176+
177+
Assert.NotNull(schema);
178+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Defs), "Argument schema should contain $defs");
179+
AssertAllRefsDefined(schema);
180+
}
181+
182+
[Fact]
183+
public void Schema_CrossAssemblyNestedClass_GeneratesValidSchema()
184+
{
185+
var reflector = new Reflector();
186+
var schema = JsonSchemaValidation(typeof(StaticParentClass.NestedClass), reflector);
187+
188+
Assert.NotNull(schema);
189+
Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString());
190+
Assert.True(schema.AsObject().ContainsKey(JsonSchema.Properties));
191+
192+
var properties = schema[JsonSchema.Properties]!.AsObject();
193+
Assert.True(properties.ContainsKey("NestedField"));
194+
Assert.True(properties.ContainsKey("NestedProperty"));
195+
}
196+
197+
private ParentClass.NestedClass NestedClassReturnMethod() => new ParentClass.NestedClass();
198+
private LevelOne.LevelTwo.LevelThree.LevelFour DeeplyNestedClassReturnMethod() => new LevelOne.LevelTwo.LevelThree.LevelFour();
199+
private GenericOuter<int>.GenericInner<string> GenericNestedClassReturnMethod() => new GenericOuter<int>.GenericInner<string>();
200+
private ParentClass.NestedClass[] NestedClassArrayReturnMethod() => new ParentClass.NestedClass[0];
201+
private void NestedClassArgumentMethod(ParentClass.NestedClass nested) { }
202+
}
203+
}

ReflectorNet.Tests/src/SchemaTests/TestSchemaTypeId.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,30 @@ public TestSchemaTypeId(ITestOutputHelper output) : base(output) { }
1212
[Fact]
1313
public void GetSchemaTypeId_NestedClass_ShouldEncodePlusSymbol()
1414
{
15-
// Arrange
1615
var type = typeof(ParentClass.NestedClass);
17-
18-
// Act
1916
var result = type.GetSchemaTypeId();
20-
21-
// Assert
2217
Assert.Equal("com.IvanMurzak.ReflectorNet.OuterAssembly.Model.ParentClass%2BNestedClass", result);
2318
_output.WriteLine($"ParentClass.NestedClass -> {result}");
2419
}
2520

21+
[Fact]
22+
public void GetSchemaTypeId_DeeplyNestedClass_ShouldEncodeAllPlusSymbols()
23+
{
24+
var type = typeof(LevelOne.LevelTwo.LevelThree.LevelFour);
25+
var result = type.GetSchemaTypeId();
26+
Assert.Equal("com.IvanMurzak.ReflectorNet.OuterAssembly.Model.LevelOne%2BLevelTwo%2BLevelThree%2BLevelFour", result);
27+
_output.WriteLine($"LevelOne.LevelTwo.LevelThree.LevelFour -> {result}");
28+
}
29+
30+
[Fact]
31+
public void GetSchemaTypeId_GenericNestedClass_ShouldEncodePlusAndAngleBrackets()
32+
{
33+
var type = typeof(GenericOuter<int>.GenericInner<string>);
34+
var result = type.GetSchemaTypeId();
35+
Assert.Equal("com.IvanMurzak.ReflectorNet.OuterAssembly.Model.GenericOuter%3CSystem.Int32%3E%2BGenericInner%3CSystem.String%3E", result);
36+
_output.WriteLine($"GenericOuter<int>.GenericInner<string> -> {result}");
37+
}
38+
2639
[Fact]
2740
public void GetSchemaTypeId_SimpleArray_ShouldAppendArray()
2841
{

0 commit comments

Comments
 (0)