From fa75f622862fb9ba76ebbf687969d453c1774ce5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 02:53:02 +0000 Subject: [PATCH 1/8] Initial plan From ed028caca986d178a8b9e0072901acb4158e3744 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 02:58:28 +0000 Subject: [PATCH 2/8] Fix SerializedMember JSON schema to accept any value type - Remove type constraint from 'value' property in SerializedMemberConverter.Schema - Add comprehensive tests in SerializedMemberSchemaTests - All 584 existing tests still pass Co-authored-by: IvanMurzak <9135028+IvanMurzak@users.noreply.github.com> --- .../SerializedMemberSchemaTests.cs | 212 ++++++++++++++++++ .../Json/SerializedMemberConverter.cs | 1 - 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs new file mode 100644 index 00000000..18883cb0 --- /dev/null +++ b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Nodes; +using com.IvanMurzak.ReflectorNet.Model; +using com.IvanMurzak.ReflectorNet.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace com.IvanMurzak.ReflectorNet.Tests.SchemaTests +{ + /// + /// Tests to validate that SerializedMember JSON schema correctly represents + /// the actual serialized JSON for various value types. + /// + public class SerializedMemberSchemaTests : BaseTest + { + public SerializedMemberSchemaTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void SerializedMember_Schema_Value_Should_Accept_Any_JsonType() + { + // Arrange + var reflector = new Reflector(); + var schema = reflector.GetSchema(); + + // Assert - Check that schema was generated + Assert.NotNull(schema); + + // Get the value property schema + var schemaObj = schema.AsObject(); + Assert.True(schemaObj.TryGetPropertyValue(JsonSchema.Properties, out var propertiesNode)); + var properties = propertiesNode!.AsObject(); + Assert.True(properties.TryGetPropertyValue(SerializedMember.ValueName, out var valueSchemaNode)); + var valueSchema = valueSchemaNode!.AsObject(); + + // The value schema should NOT have a "type" constraint + // This allows it to accept any JSON value type + Assert.False(valueSchema.TryGetPropertyValue(JsonSchema.Type, out _), + "The 'value' property schema should not have a 'type' constraint to allow any JSON value type"); + + // It should have a description + Assert.True(valueSchema.TryGetPropertyValue(JsonSchema.Description, out var descriptionNode)); + Assert.NotNull(descriptionNode); + + _output.WriteLine($"✓ SerializedMember schema allows 'value' to be any JSON type"); + _output.WriteLine($"Schema:\n{schema.ToJsonString(new JsonSerializerOptions { WriteIndented = true })}"); + } + + [Theory] + [InlineData("test string", "string")] + [InlineData(42, "number")] + [InlineData(3.14, "number")] + [InlineData(true, "boolean")] + [InlineData(false, "boolean")] + public void SerializedMember_Should_Serialize_PrimitiveTypes_Correctly(object value, string expectedJsonType) + { + // Arrange + var reflector = new Reflector(); + + // Act + var serialized = reflector.Serialize(value, name: "testValue"); + var json = serialized.ToJson(reflector); + + // Parse and validate JSON structure + var jsonNode = JsonNode.Parse(json); + Assert.NotNull(jsonNode); + + var jsonObj = jsonNode!.AsObject(); + Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); + Assert.NotNull(valueNode); + + // Validate the value type matches expected + var actualJsonType = GetJsonValueType(valueNode); + _output.WriteLine($"Value: {value}, Expected type: {expectedJsonType}, Actual type: {actualJsonType}"); + _output.WriteLine($"Serialized JSON: {json}"); + + Assert.Equal(expectedJsonType, actualJsonType); + } + + [Fact] + public void SerializedMember_Should_Serialize_Null_Correctly() + { + // Arrange + var reflector = new Reflector(); + + // Act + var serialized = reflector.Serialize(null, typeof(string), name: "testValue"); + var json = serialized.ToJson(reflector); + + // Parse and validate JSON structure + var jsonNode = JsonNode.Parse(json); + Assert.NotNull(jsonNode); + + var jsonObj = jsonNode!.AsObject(); + + // For null values, the value property should be absent or null + if (jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)) + { + Assert.Null(valueNode); + } + + _output.WriteLine($"Serialized null value JSON: {json}"); + } + + [Fact] + public void SerializedMember_Should_Serialize_Array_Correctly() + { + // Arrange + var reflector = new Reflector(); + var array = new[] { 1, 2, 3 }; + + // Act + var serialized = reflector.Serialize(array, name: "testArray"); + var json = serialized.ToJson(reflector); + + // Parse and validate JSON structure + var jsonNode = JsonNode.Parse(json); + Assert.NotNull(jsonNode); + + var jsonObj = jsonNode!.AsObject(); + Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); + Assert.NotNull(valueNode); + + // The value should be a JSON array + Assert.IsType(valueNode); + + _output.WriteLine($"Serialized array JSON: {json}"); + } + + [Fact] + public void SerializedMember_Should_Serialize_Object_Correctly() + { + // Arrange + var reflector = new Reflector(); + var obj = new TestClass { Name = "Test", Value = 123 }; + + // Act + var serialized = reflector.Serialize(obj, name: "testObject"); + var json = serialized.ToJson(reflector); + + // Parse and validate JSON structure + var jsonNode = JsonNode.Parse(json); + Assert.NotNull(jsonNode); + + var jsonObj = jsonNode!.AsObject(); + Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); + Assert.NotNull(valueNode); + + // For complex objects, the value is typically an empty object {} + // and the actual data is in props/fields + Assert.IsType(valueNode); + + _output.WriteLine($"Serialized object JSON: {json}"); + } + + [Fact] + public void SerializedMember_RoundTrip_Should_Preserve_AllValueTypes() + { + // Arrange + var reflector = new Reflector(); + var testValues = new object[] + { + "string value", + 42, + 3.14159, + true, + false + }; + + foreach (var originalValue in testValues) + { + // Act + var serialized = reflector.Serialize(originalValue, name: "test"); + var deserialized = reflector.Deserialize(serialized); + + // Assert + var originalJson = originalValue.ToJson(reflector); + var deserializedJson = deserialized.ToJson(reflector); + + _output.WriteLine($"Original: {originalValue} ({originalValue.GetType().Name})"); + _output.WriteLine($"Original JSON: {originalJson}"); + _output.WriteLine($"Deserialized JSON: {deserializedJson}"); + + Assert.Equal(originalJson, deserializedJson); + } + } + + /// + /// Helper method to determine the JSON value type from a JsonNode + /// + private string GetJsonValueType(JsonNode node) + { + return node switch + { + JsonObject => "object", + JsonArray => "array", + JsonValue value when value.TryGetValue(out _) => "string", + JsonValue value when value.TryGetValue(out _) => "boolean", + JsonValue value when value.TryGetValue(out _) || value.TryGetValue(out _) || + value.TryGetValue(out _) || value.TryGetValue(out _) => "number", + _ => "unknown" + }; + } + + private class TestClass + { + public string Name { get; set; } = string.Empty; + public int Value { get; set; } + } + } +} diff --git a/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs b/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs index 4f818b8d..501c5beb 100644 --- a/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs +++ b/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs @@ -40,7 +40,6 @@ public class SerializedMemberConverter : JsonSchemaConverter, }, [SerializedMember.ValueName] = new JsonObject { - [JsonSchema.Type] = JsonSchema.Object, [JsonSchema.Description] = TypeUtils.GetDescription( typeof(SerializedMember) .GetMember(nameof(SerializedMember.valueJsonElement)) From 7f0a91a41b286670bd71a92516e7272ab8f088da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 03:01:41 +0000 Subject: [PATCH 3/8] Improve numeric type detection in SerializedMemberSchemaTests - Extract numeric detection logic into separate IsNumericJsonValue method - Add support for all numeric types (float, byte, short, uint, ulong, ushort, sbyte) Co-authored-by: IvanMurzak <9135028+IvanMurzak@users.noreply.github.com> --- .../SerializedMemberSchemaTests.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs index 18883cb0..49a75bd2 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs @@ -197,12 +197,29 @@ private string GetJsonValueType(JsonNode node) JsonArray => "array", JsonValue value when value.TryGetValue(out _) => "string", JsonValue value when value.TryGetValue(out _) => "boolean", - JsonValue value when value.TryGetValue(out _) || value.TryGetValue(out _) || - value.TryGetValue(out _) || value.TryGetValue(out _) => "number", + JsonValue value when IsNumericJsonValue(value) => "number", _ => "unknown" }; } + /// + /// Helper method to check if a JsonValue represents a numeric type + /// + private bool IsNumericJsonValue(JsonValue value) + { + return value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _) || + value.TryGetValue(out _); + } + private class TestClass { public string Name { get; set; } = string.Empty; From 985a7d43e52118cd1a9228baa3c9838b66354d82 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 7 Dec 2025 00:04:12 -0800 Subject: [PATCH 4/8] Remove unnecessary value name from SerializedMember JSON schema requirements --- ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs b/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs index 501c5beb..1365c046 100644 --- a/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs +++ b/ReflectorNet/src/Convertor/Json/SerializedMemberConverter.cs @@ -72,7 +72,7 @@ public class SerializedMemberConverter : JsonSchemaConverter, .First()) } }, - [JsonSchema.Required] = new JsonArray { nameof(SerializedMember.typeName), SerializedMember.ValueName }, + [JsonSchema.Required] = new JsonArray { nameof(SerializedMember.typeName) }, [JsonSchema.AdditionalProperties] = false }; public static JsonNode SchemaRef => new JsonObject From 2bc71f99e31207736392c56cea36187f408b8c63 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 7 Dec 2025 00:13:22 -0800 Subject: [PATCH 5/8] Enable inclusion of public fields in JSON serialization --- ReflectorNet/src/Utils/Json/JsonSerializer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ReflectorNet/src/Utils/Json/JsonSerializer.cs b/ReflectorNet/src/Utils/Json/JsonSerializer.cs index 5342d411..611e55a6 100644 --- a/ReflectorNet/src/Utils/Json/JsonSerializer.cs +++ b/ReflectorNet/src/Utils/Json/JsonSerializer.cs @@ -80,6 +80,7 @@ public JsonSerializer(Reflector reflector) // ReferenceHandler = ReferenceHandler.Preserve, PropertyNamingPolicy = null, PropertyNameCaseInsensitive = true, + IncludeFields = true, // Include public fields in serialization WriteIndented = true, TypeInfoResolver = JsonTypeInfoResolver.Combine( new DefaultJsonTypeInfoResolver() From 451d60b53b9c1edbbe0c4a10b1202a6c0d9410af Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 7 Dec 2025 00:21:29 -0800 Subject: [PATCH 6/8] Simplify JSON schema output formatting in SerializedMemberSchemaTests --- .../src/SchemaTests/SerializedMemberSchemaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs index 49a75bd2..6ee961ea 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs @@ -44,7 +44,7 @@ public void SerializedMember_Schema_Value_Should_Accept_Any_JsonType() Assert.NotNull(descriptionNode); _output.WriteLine($"✓ SerializedMember schema allows 'value' to be any JSON type"); - _output.WriteLine($"Schema:\n{schema.ToJsonString(new JsonSerializerOptions { WriteIndented = true })}"); + _output.WriteLine($"Schema:\n{schema.ToJsonString()}"); } [Theory] From 672865c0c888bd5e6111b5b4d0afe1904939a4f7 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 7 Dec 2025 00:23:01 -0800 Subject: [PATCH 7/8] Refactor SerializedMemberSchemaTests to remove unnecessary using directives and clean up whitespace --- .../SerializedMemberSchemaTests.cs | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs index 6ee961ea..acc525ff 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; using System.Text.Json.Nodes; using com.IvanMurzak.ReflectorNet.Model; using com.IvanMurzak.ReflectorNet.Utils; -using Xunit; using Xunit.Abstractions; namespace com.IvanMurzak.ReflectorNet.Tests.SchemaTests @@ -26,7 +22,7 @@ public void SerializedMember_Schema_Value_Should_Accept_Any_JsonType() // Assert - Check that schema was generated Assert.NotNull(schema); - + // Get the value property schema var schemaObj = schema.AsObject(); Assert.True(schemaObj.TryGetPropertyValue(JsonSchema.Properties, out var propertiesNode)); @@ -61,11 +57,11 @@ public void SerializedMember_Should_Serialize_PrimitiveTypes_Correctly(object va // Act var serialized = reflector.Serialize(value, name: "testValue"); var json = serialized.ToJson(reflector); - + // Parse and validate JSON structure var jsonNode = JsonNode.Parse(json); Assert.NotNull(jsonNode); - + var jsonObj = jsonNode!.AsObject(); Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); Assert.NotNull(valueNode); @@ -74,7 +70,7 @@ public void SerializedMember_Should_Serialize_PrimitiveTypes_Correctly(object va var actualJsonType = GetJsonValueType(valueNode); _output.WriteLine($"Value: {value}, Expected type: {expectedJsonType}, Actual type: {actualJsonType}"); _output.WriteLine($"Serialized JSON: {json}"); - + Assert.Equal(expectedJsonType, actualJsonType); } @@ -87,19 +83,19 @@ public void SerializedMember_Should_Serialize_Null_Correctly() // Act var serialized = reflector.Serialize(null, typeof(string), name: "testValue"); var json = serialized.ToJson(reflector); - + // Parse and validate JSON structure var jsonNode = JsonNode.Parse(json); Assert.NotNull(jsonNode); - + var jsonObj = jsonNode!.AsObject(); - + // For null values, the value property should be absent or null if (jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)) { Assert.Null(valueNode); } - + _output.WriteLine($"Serialized null value JSON: {json}"); } @@ -113,18 +109,18 @@ public void SerializedMember_Should_Serialize_Array_Correctly() // Act var serialized = reflector.Serialize(array, name: "testArray"); var json = serialized.ToJson(reflector); - + // Parse and validate JSON structure var jsonNode = JsonNode.Parse(json); Assert.NotNull(jsonNode); - + var jsonObj = jsonNode!.AsObject(); Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); Assert.NotNull(valueNode); // The value should be a JSON array Assert.IsType(valueNode); - + _output.WriteLine($"Serialized array JSON: {json}"); } @@ -138,11 +134,11 @@ public void SerializedMember_Should_Serialize_Object_Correctly() // Act var serialized = reflector.Serialize(obj, name: "testObject"); var json = serialized.ToJson(reflector); - + // Parse and validate JSON structure var jsonNode = JsonNode.Parse(json); Assert.NotNull(jsonNode); - + var jsonObj = jsonNode!.AsObject(); Assert.True(jsonObj.TryGetPropertyValue(SerializedMember.ValueName, out var valueNode)); Assert.NotNull(valueNode); @@ -150,7 +146,7 @@ public void SerializedMember_Should_Serialize_Object_Correctly() // For complex objects, the value is typically an empty object {} // and the actual data is in props/fields Assert.IsType(valueNode); - + _output.WriteLine($"Serialized object JSON: {json}"); } @@ -177,11 +173,11 @@ public void SerializedMember_RoundTrip_Should_Preserve_AllValueTypes() // Assert var originalJson = originalValue.ToJson(reflector); var deserializedJson = deserialized.ToJson(reflector); - + _output.WriteLine($"Original: {originalValue} ({originalValue.GetType().Name})"); _output.WriteLine($"Original JSON: {originalJson}"); _output.WriteLine($"Deserialized JSON: {deserializedJson}"); - + Assert.Equal(originalJson, deserializedJson); } } @@ -207,10 +203,10 @@ JsonValue value when IsNumericJsonValue(value) => "number", /// private bool IsNumericJsonValue(JsonValue value) { - return value.TryGetValue(out _) || - value.TryGetValue(out _) || + return value.TryGetValue(out _) || + value.TryGetValue(out _) || value.TryGetValue(out _) || - value.TryGetValue(out _) || + value.TryGetValue(out _) || value.TryGetValue(out _) || value.TryGetValue(out _) || value.TryGetValue(out _) || From 94f422a6c7dd84fd8f100eff0a99e49a861f163b Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 7 Dec 2025 00:28:02 -0800 Subject: [PATCH 8/8] Fix JSON value type detection order in GetJsonValueType method --- .../src/SchemaTests/SerializedMemberSchemaTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs index acc525ff..5b60a1fc 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SerializedMemberSchemaTests.cs @@ -191,9 +191,9 @@ private string GetJsonValueType(JsonNode node) { JsonObject => "object", JsonArray => "array", - JsonValue value when value.TryGetValue(out _) => "string", JsonValue value when value.TryGetValue(out _) => "boolean", JsonValue value when IsNumericJsonValue(value) => "number", + JsonValue value when value.TryGetValue(out _) => "string", _ => "unknown" }; }