NJsonSchema icon indicating copy to clipboard operation
NJsonSchema copied to clipboard

Array Items $ref stop working after 2 levels of nesting after v10.2.0

Open zane-woodard-drc opened this issue 2 years ago • 0 comments

I recently upgraded an old project and some test cases broke. After debugging the test cases, they were failing due to JSONSchema.Item.Reference being null when it previously correctly resolved to a referenced schema. After trying a bunch of different versions, it looks like this broke in v10.2.0. Most likely cause by this commit, although I don't really understand why.

I put together this minimal repro to show the issue. For a schema with just 2 levels of nesting, it appears that the $ref is still correctly resolved. However, add 1 more level and suddenly NJsonSchema cannot resolve the reference. Other JsonSchema tools such as https://www.jsonschemavalidator.net/ seem to be able to resolve it without issue.

Here is the test case:

using Newtonsoft.Json.Linq;
using NJsonSchema;
using System.Threading.Tasks;
using Xunit;

namespace Validation.Core.Test
{
    public class ArrayRefNotResolving_External_TestCase
    {
        [Fact]
        public async Task Should_Fail_Validation_Working()
        {
            var testSchema = await JsonSchema.FromJsonAsync(workingSchemaJson);

            var jObj = JObject.FromObject(
                new
                {
                    TopLevel = new
                    {
                        BottomLevel = new object[] {
                            new { ExampleRequiredField = "foo" },
                            new { ExampleRequiredField = 123 },
                        },
                    }
                }
            );

            var results = testSchema.Validate(jObj);

            //Should contain 1 error as ExampleRequiredField must be a string
            Assert.True(results.Count == 1);
        }

        [Fact]
        public async Task Should_Fail_Validation_Broken()
        {
            var testSchema = await JsonSchema.FromJsonAsync(brokenSchemaJson);

            var jObj = JObject.FromObject(
                new
                {
                    TopLevel = new
                    {
                        MidLevel = new {
                            BottomLevel = new object[] {
                                new { ExampleRequiredField = "foo" },
                                new { ExampleRequiredField = 123 },
                            },
                        }
                    }
                }
            );

            var results = testSchema.Validate(jObj);

            //Should contain 1 error as ExampleRequiredField must be a string
            Assert.True(results.Count == 1);
        }

        string workingSchemaJson = @"
        {
            ""$schema"": ""http://json-schema.org/draft-07/schema"",
            ""$id"": ""http://example.com/example.json"",
            ""required"": [
              ""TopLevel""
            ],
            ""properties"": {
              ""TopLevel"": {
                ""$id"": ""#/properties/TopLevel"",
                ""type"": ""object"",
                ""required"": [
                  ""BottomLevel""
                ],
                ""properties"": {
                  ""BottomLevel"": {
                    ""$id"": ""#/properties/BottomLevel"",
                    ""type"": ""array"",
                    ""items"": {
                      ""$ref"": ""#/inputs/BottomLevel""
                    }
                  }
                }
              }
            },
            ""inputs"": {
              ""BottomLevel"": {
                ""additionalProperties"": true,
                ""$id"": ""#/inputs/BottomLevel"",
                ""type"": ""object"",
                ""required"": [
                  ""ExampleRequiredField""
                ],
                ""properties"": {
                  ""ExampleRequiredField"": {
                    ""$id"": ""#/properties/ExampleRequiredField"",
                    ""name"": ""ExampleRequiredField"",
                    ""type"": ""string""
                  }
                }
              }
            }
          }
        ";

        string brokenSchemaJson = @"
        {
          ""$schema"": ""http://json-schema.org/draft-07/schema"",
          ""$id"": ""http://example.com/example.json"",
          ""title"": ""Test Schema"",
          ""required"": [
            ""TopLevel""
          ],
          ""properties"": {
            ""TopLevel"": {
              ""$id"": ""#/properties/TopLevel"",
              ""type"": ""object"",
              ""required"": [
                ""MidLevel""
              ],
              ""properties"": {
                ""MidLevel"": {
                  ""$ref"": ""#/inputs/MidLevel""
                }
              }
            }
          },
          ""inputs"": {
            ""BottomLevel"": {
              ""$id"": ""#/inputs/BottomLevel"",
              ""type"": ""object"",
              ""required"": [
                ""ExampleRequiredField""
              ],
              ""properties"": {
                ""ExampleRequiredField"": {
                  ""$id"": ""#/properties/ExampleRequiredField"",
                  ""name"": ""ExampleRequiredField"",
                  ""type"": ""string""
                }
              }
            },
            ""MidLevel"": {
              ""$id"": ""#/inputs/MidLevel"",
              ""type"": ""object"",
              ""required"": [
                ""BottomLevel""
              ],
              ""properties"": {
                ""BottomLevel"": {
                  ""$id"": ""#/properties/BottomLevel"",
                  ""type"": ""array"",
                  ""items"": {
                    ""$ref"": ""#/inputs/BottomLevel""
                  }
                }
              }
            }
          }
        }
        ";
    }
}

Searching around, a few others seem to have had this issue, although for them it is manifesting as an error like this: System.InvalidOperationException : The schema reference path '#/inputs/BottomLevel' has not been resolved.

zane-woodard-drc avatar Apr 18 '22 22:04 zane-woodard-drc