diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 32603f160f8..ecb3e0c21d0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -264,19 +264,11 @@ protected override void ProcessRecord() if (_jschema != null) { - EvaluationResults evaluationResults = _jschema.Evaluate(parsedJson, new EvaluationOptions { OutputFormat = OutputFormat.List }); + EvaluationResults evaluationResults = _jschema.Evaluate(parsedJson, new EvaluationOptions { OutputFormat = OutputFormat.Hierarchical }); result = evaluationResults.IsValid; if (!result) { HandleValidationErrors(evaluationResults); - - if (evaluationResults.HasDetails) - { - foreach (var nestedResult in evaluationResults.Details) - { - HandleValidationErrors(nestedResult); - } - } } } } @@ -300,16 +292,27 @@ protected override void ProcessRecord() private void HandleValidationErrors(EvaluationResults evaluationResult) { - if (!evaluationResult.HasErrors) + if (evaluationResult.IsValid) { return; } - foreach (var error in evaluationResult.Errors!) + if (evaluationResult.HasErrors) + { + foreach (var error in evaluationResult.Errors!) + { + Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, error.Value, evaluationResult.InstanceLocation)); + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null); + WriteError(errorRecord); + } + } + + if (evaluationResult.HasDetails) { - Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, error.Value, evaluationResult.InstanceLocation)); - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null); - WriteError(errorRecord); + foreach (var nestedResult in evaluationResult.Details) + { + HandleValidationErrors(nestedResult); + } } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 index 32a6cf3ce63..6d27cba9f95 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -86,6 +86,95 @@ Describe "Test-Json" -Tags "CI" { } '@ + $oneOfSchemaJson = @' + { + "type": "object", + "properties" : { + "Devices": { + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { + "properties": { + "id": { "type": "string" }, + "deviceType": { "const": "smartphone" }, + "os": { "type": "string", "enum": ["iOS", "Android" ] } + }, + "required": ["deviceType", "os"] + }, + { + "properties": { + "id": { "type": "string" }, + "deviceType": { "const": "laptop" }, + "arch": { "type": "string", "enum": ["x86", "x64", "arm64"] } + }, + "required": ["deviceType", "arch"] + } + ] + } + } + }, + "required": [ "Devices"] + } + +'@ + + $jsonValidOneOf = @' + { + "Devices": [ + { + "id": "0", + "deviceType": "laptop", + "arch": "x64" + }, + { + "id": "1", + "deviceType": "smartphone", + "os": "iOS" + }, + { + "id": "2", + "deviceType": "laptop", + "arch": "arm64" + }, + { + "id": "3", + "deviceType": "smartphone", + "os": "Android" + } + ] + } +'@ + + $jsonInvalidOneOf = @' + { + "Devices": [ + { + "id": "0", + "deviceType": "laptop", + "arch": "x64" + }, + { + "id": "1", + "deviceType": "smartphone", + "os": "iOS" + }, + { + "id": "2", + "deviceType": "laptop", + "arch": "arm64" + }, + { + "id": "3", + "deviceType": "smartphone", + "os": "WindowsPhone" + } + ] + } +'@ + + $validJsonPath = Join-Path -Path $TestDrive -ChildPath 'validJson.json' $validLiteralJsonPath = Join-Path -Path $TestDrive -ChildPath "[valid]Json.json" $invalidNodeInJsonPath = Join-Path -Path $TestDrive -ChildPath 'invalidNodeInJson.json' @@ -181,6 +270,21 @@ Describe "Test-Json" -Tags "CI" { Test-Json -Path $invalidNodeInJsonPath -ErrorAction SilentlyContinue | Should -BeFalse } + It "OneOf invalid json only reports real errors" { + $errVar = @() + Test-Json -Json $jsonInvalidOneOf -Schema $oneOfSchemaJson -ErrorAction SilentlyContinue -ErrorVariable errVar + + $falseErrors = $errVar | select-string -pattern "Devices\/(0|1|2)" + $falseErrors.Count | Should -Be 0 + + $realErrors = $errVar | select-string -pattern "Devices\/3" + $realErrors.Count | Should -BeGreaterThan 0 + } + + It "OneOf valid json should succeed" { + Test-Json -Json $jsonValidOneOf -Schema $oneOfSchemaJson -ErrorAction SilentlyContinue | Should -BeTrue + } + It "Json file is invalid against a valid schema from string" { Test-Json -Path $invalidTypeInJson2Path -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse Test-Json -Path $invalidNodeInJsonPath -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse