From 50def0b4432f1b9c8b4dd6587a0f3098354e194e Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sun, 4 Sep 2022 09:23:52 +1200 Subject: [PATCH 01/58] updated Test-Json cmdlet to use JsonSchema.Net instead of NJsonSchema --- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- .../commands/utility/TestJsonCommand.cs | 124 +++--------------- 2 files changed, 20 insertions(+), 106 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index e9c7c102290..c7ad6fb7711 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -35,7 +35,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index fc416d9772e..242a4595c30 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -4,75 +4,32 @@ using System; using System.Globalization; using System.IO; +using System.Linq; using System.Management.Automation; using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; -using Newtonsoft.Json.Linq; -using NJsonSchema; +using System.Text.Json.Nodes; +using Json.Schema; namespace Microsoft.PowerShell.Commands { /// /// This class implements Test-Json command. /// - [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = JsonStringParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096609")] + [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096609")] [OutputType(typeof(bool))] public class TestJsonCommand : PSCmdlet { - #region Parameter Set Names - - private const string JsonStringParameterSet = "JsonString"; - private const string JsonStringWithSchemaStringParameterSet = "JsonStringWithSchemaString"; - private const string JsonStringWithSchemaFileParameterSet = "JsonStringWithSchemaFile"; - private const string JsonPathParameterSet = "JsonPath"; - private const string JsonPathWithSchemaStringParameterSet = "JsonPathWithSchemaString"; - private const string JsonPathWithSchemaFileParameterSet = "JsonPathWithSchemaFile"; - private const string JsonLiteralPathParameterSet = "JsonLiteralPath"; - private const string JsonLiteralPathWithSchemaStringParameterSet = "JsonLiteralPathWithSchemaString"; - private const string JsonLiteralPathWithSchemaFileParameterSet = "JsonLiteralPathWithSchemaFile"; - - #endregion - - #region Parameters + private const string SchemaFileParameterSet = "SchemaFile"; + private const string SchemaStringParameterSet = "SchemaString"; /// /// Gets or sets JSON string to be validated. /// - [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ParameterSetName = JsonStringParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ParameterSetName = JsonStringWithSchemaStringParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ParameterSetName = JsonStringWithSchemaFileParameterSet)] + [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] public string Json { get; set; } - /// - /// Gets or sets JSON file path to be validated. - /// - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonPathParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonPathWithSchemaStringParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonPathWithSchemaFileParameterSet)] - public string Path { get; set; } - - /// - /// Gets or sets JSON literal file path to be validated. - /// - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonLiteralPathParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonLiteralPathWithSchemaStringParameterSet)] - [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = JsonLiteralPathWithSchemaFileParameterSet)] - [Alias("PSPath", "LP")] - public string LiteralPath - { - get - { - return _isLiteralPath ? Path : null; - } - - set - { - _isLiteralPath = true; - Path = value; - } - } - /// /// Gets or sets schema to validate the JSON against. /// This is optional parameter. @@ -81,9 +38,7 @@ public string LiteralPath /// then validates the JSON against the schema. Before testing the JSON string, /// the cmdlet parses the schema doing implicitly check the schema too. /// - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonStringWithSchemaStringParameterSet)] - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonPathWithSchemaStringParameterSet)] - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonLiteralPathWithSchemaStringParameterSet)] + [Parameter(Position = 1, ParameterSetName = SchemaStringParameterSet)] [ValidateNotNullOrEmpty] public string Schema { get; set; } @@ -91,17 +46,10 @@ public string LiteralPath /// Gets or sets path to the file containing schema to validate the JSON string against. /// This is optional parameter. /// - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonStringWithSchemaFileParameterSet)] - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonPathWithSchemaFileParameterSet)] - [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonLiteralPathWithSchemaFileParameterSet)] + [Parameter(Position = 1, ParameterSetName = SchemaFileParameterSet)] [ValidateNotNullOrEmpty] public string SchemaFile { get; set; } - #endregion - - #region Private Members - - private bool _isLiteralPath = false; private JsonSchema _jschema; /// @@ -125,10 +73,6 @@ private static bool UnwrapException(Exception e) return true; } - #endregion - - #region Protected Members - /// /// Prepare a JSON schema. /// @@ -142,7 +86,7 @@ protected override void BeginProcessing() { try { - _jschema = JsonSchema.FromJsonAsync(Schema).Result; + _jschema = JsonSchema.FromText(Schema); } catch (AggregateException ae) { @@ -156,7 +100,7 @@ protected override void BeginProcessing() try { resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); - _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; + _jschema = JsonSchema.FromFile(resolvedpath); } catch (AggregateException ae) { @@ -194,52 +138,24 @@ e is SecurityException protected override void ProcessRecord() { bool result = true; - string jsonToParse = string.Empty; - - if (Json != null) - { - jsonToParse = Json; - } - else if (Path != null) - { - string resolvedPath = PathUtils.ResolveFilePath(Path, this, _isLiteralPath); - - if (!File.Exists(resolvedPath)) - { - ItemNotFoundException exception = new( - Path, - "PathNotFound", - SessionStateStrings.PathNotFound); - - ThrowTerminatingError(exception.ErrorRecord); - } - - jsonToParse = File.ReadAllText(resolvedPath); - } - - if (string.IsNullOrWhiteSpace(jsonToParse)) - { - WriteObject(false); - return; - } try { - var parsedJson = JToken.Parse(jsonToParse); + var parsedJson = JsonNode.Parse(Json); if (_jschema != null) { - var errorMessages = _jschema.Validate(parsedJson); - if (errorMessages != null && errorMessages.Count != 0) + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions{OutputFormat = OutputFormat.Basic}); + result = validationResults.IsValid; + if (validationResults.NestedResults.Count != 0) { - result = false; - Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - foreach (var message in errorMessages) + foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) { ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - errorRecord.ErrorDetails = new ErrorDetails(message.ToString()); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); } } @@ -250,12 +166,10 @@ protected override void ProcessRecord() result = false; Exception exception = new(TestJsonCmdletStrings.InvalidJson, exc); - WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, jsonToParse)); + WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, Json)); } WriteObject(result); } - - #endregion } } From 3fd0a8a7cb201d08be352ead11627c0500d505e1 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 6 Sep 2022 11:29:19 +1200 Subject: [PATCH 02/58] change quoting of test-json tests --- .../Test-Json.Tests.ps1 | 213 ++++-------------- 1 file changed, 39 insertions(+), 174 deletions(-) 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 9e949e0215a..d2e3c52da6b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -3,201 +3,110 @@ Describe "Test-Json" -Tags "CI" { BeforeAll { - $assetsPath = Join-Path $PSScriptRoot -ChildPath assets - $validSchemaJsonPath = Join-Path -Path $assetsPath -ChildPath valid_schema_reference.json - $invalidSchemaJsonPath = Join-Path -Path $assetsPath -ChildPath invalid_schema_reference.json - $missingSchemaJsonPath = Join-Path -Path $assetsPath -ChildPath no_such_file.json - $missingJsonPath = Join-Path -Path $assetsPath -ChildPath no_such_file.json + $validSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath valid_schema_reference.json - $validSchemaJson = @" + $invalidSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath invalid_schema_reference.json + + $missingSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath no_such_file.json + + $validSchemaJson = @' { - 'description': 'A person', - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'hobbies': { - 'type': 'array', - 'items': {'type': 'string'} + "description": "A person", + "type": "object", + "properties": { + "name": {"type": "string"}, + "hobbies": { + "type": "array", + "items": {"type": "string"} } } } -"@ +'@ - $invalidSchemaJson = @" + $invalidSchemaJson = @' { - 'description', - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'hobbies': { - 'type': 'array', - 'items': {'type': 'string'} + "description", + "type": "object", + "properties": { + "name": {"type": "string"}, + "hobbies": { + "type": "array", + "items": {"type": "string"} } } } -"@ +'@ - $validJson = @" + $validJson = @' { - 'name': 'James', - 'hobbies': ['.NET', 'Blogging', 'Reading', 'Xbox', 'LOLCATS'] + "name": "James", + "hobbies": [".NET", "Blogging", "Reading", "Xbox", "LOLCATS"] } -"@ +'@ - $invalidTypeInJson = @" + $invalidTypeInJson = @' { - 'name': 123, - 'hobbies': ['.NET', 'Blogging', 'Reading', 'Xbox', 'LOLCATS'] + "name": 123, + "hobbies": [".NET", "Blogging", "Reading", "Xbox", "LOLCATS"] } -"@ +'@ - $invalidTypeInJson2 = @" + $invalidTypeInJson2 = @' { - 'name': 123, - 'hobbies': [456, 'Blogging', 'Reading', 'Xbox', 'LOLCATS'] + "name": 123, + "hobbies": [456, "Blogging", "Reading", "Xbox", "LOLCATS"] } -"@ +'@ - $invalidNodeInJson = @" + $invalidNodeInJson = @' { - 'name': 'James', - 'hobbies': ['.NET', 'Blogging', 'Reading', 'Xbox', 'LOLCATS'] + "name": "James", + "hobbies": [".NET", "Blogging", "Reading", "Xbox", "LOLCATS"] errorNode } -"@ - - $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' - $invalidTypeInJsonPath = Join-Path -Path $TestDrive -ChildPath 'invalidTypeInJson.json' - $invalidTypeInJson2Path = Join-Path -Path $TestDrive -ChildPath 'invalidTypeInJson2.json' - $invalidEmptyJsonPath = Join-Path -Path $TestDrive -ChildPath 'emptyJson.json' - - Set-Content -Path $validJsonPath -Value $validJson - Set-Content -LiteralPath $validLiteralJsonPath -Value $validJson - Set-Content -Path $invalidNodeInJsonPath -Value $invalidNodeInJson - Set-Content -Path $invalidTypeInJsonPath -Value $invalidTypeInJson - Set-Content -Path $invalidTypeInJson2Path -Value $invalidTypeInJson2 - New-Item -Path $invalidEmptyJsonPath -ItemType File +'@ } It "Missing JSON schema file doesn't exist" { Test-Path -LiteralPath $missingSchemaJsonPath | Should -BeFalse } - It "Missing JSON file doesn't exist" { - Test-Path -LiteralPath $missingJsonPath | Should -BeFalse - } - It "Json is valid" { Test-Json -Json $validJson | Should -BeTrue - ($validJson | Test-Json) | Should -BeTrue } It "Json is valid against a valid schema from string" { Test-Json -Json $validJson -Schema $validSchemaJson | Should -BeTrue - ($validJson | Test-Json -Schema $validSchemaJson) | Should -BeTrue } It "Json is valid against a valid schema from file" { Test-Json -Json $validJson -SchemaFile $validSchemaJsonPath | Should -BeTrue - ($validJson | Test-Json -SchemaFile $validSchemaJsonPath) | Should -BeTrue - } - - It "Json file specified using -Path is valid" { - Test-Json -Path $validJsonPath | Should -BeTrue - } - - It "Json file specified using -LiteralPath is valid" { - Test-Json -LiteralPath $validLiteralJsonPath | Should -BeTrue - } - - It "Json file specified using LiteralPath aliases -PSPath and -LP is valid" { - Test-Json -PSPath $validLiteralJsonPath | Should -BeTrue - Test-Json -LP $validLiteralJsonPath | Should -BeTrue - } - - It "Json file specified using -Path from pipeline is valid" { - (Get-ChildItem -Path $validJsonPath -File | Test-Json) | Should -BeTrue - } - - It "Json file specified using -LiteralPath from pipeline is valid" { - (Get-ChildItem -LiteralPath $validLiteralJsonPath -File | Test-Json) | Should -BeTrue - } - - It "Json file is valid against a valid schema from string" { - Test-Json -Path $validJsonPath -Schema $validSchemaJson | Should -BeTrue - } - - It "Json file is valid against a valid schema from file" { - Test-Json -Path $validJsonPath -SchemaFile $validSchemaJsonPath | Should -BeTrue } It "Json is invalid" { Test-Json -Json $invalidNodeInJson -ErrorAction SilentlyContinue | Should -BeFalse - ($invalidNodeInJson | Test-Json -ErrorAction SilentlyContinue) | Should -BeFalse } It "Json is invalid against a valid schema from string" { Test-Json -Json $invalidTypeInJson2 -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse - ($invalidTypeInJson2 | Test-Json -Schema $validSchemaJson -ErrorAction SilentlyContinue) | Should -BeFalse - Test-Json -Json $invalidNodeInJson -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse - ($invalidNodeInJson | Test-Json -Schema $validSchemaJson -ErrorAction SilentlyContinue) | Should -BeFalse } It "Json is invalid against a valid schema from file" { Test-Json -Json $invalidTypeInJson2 -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - ($invalidTypeInJson2 | Test-Json -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue) | Should -BeFalse - Test-Json -Json $invalidNodeInJson -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - ($invalidNodeInJson | Test-Json -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue) | Should -BeFalse - } - - It "Json file is invalid against a valid schema from file" { - Test-Json -Path $invalidTypeInJson2Path -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - Test-Json -Path $invalidNodeInJsonPath -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - } - - It "Json file is invalid" { - Test-Json -Path $invalidNodeInJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - } - - 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 - } - - It "Json file is invalid against an empty file" { - Test-Json -Path $invalidEmptyJsonPath -ErrorAction SilentlyContinue | Should -BeFalse } It "Test-Json throw if a schema from string is invalid" { { Test-Json -Json $validJson -Schema $invalidSchemaJson -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - { Test-Json -Path $validJsonPath -Schema $invalidSchemaJson -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } It "Test-Json throw if a schema from file is invalid" { { Test-Json -Json $validJson -SchemaFile $invalidSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - { Test-Json -Path $validJsonPath -SchemaFile $invalidSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } It "Test-Json throw if a path to a schema from file is invalid" { { Test-Json -Json $validJson -SchemaFile $missingSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "JsonSchemaFileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" - { Test-Json -Path $validJsonPath -SchemaFile $missingSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "JsonSchemaFileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" - } - - It "Test-Json throw if a path from file is invalid" { - { Test-Json -Path $missingJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.TestJsonCommand" - } - - It "Test-Json throw if a path from file using -Path is a literal path" { - { Test-Json -Path $validLiteralJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "FileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" - } - - It "Json file throw if a path from file using -LiteralPath is a wildcard or regular expression" { - { Test-Json -LiteralPath (Join-Path -Path $TestDrive -ChildPath "*Json.json") -ErrorAction Stop } | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.TestJsonCommand" - { Test-Json -LiteralPath (Join-Path -Path $TestDrive -ChildPath "[a-z]Json.json") -ErrorAction Stop } | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.TestJsonCommand" } It "Test-Json write an error on invalid () Json against a valid schema from string" -TestCases @( @@ -224,30 +133,6 @@ Describe "Test-Json" -Tags "CI" { $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId } - It "Test-Json write an error on invalid () Json file against a valid schema from string" -TestCases @( - @{ name = "type"; json = $invalidTypeInJsonPath; errorId = "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } - @{ name = "node"; json = $invalidNodeInJsonPath; errorId = "InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand" } - ) { - param ($json, $errorId) - - $errorVar = $null - Test-Json -Path $json -Schema $validSchemaJson -ErrorVariable errorVar -ErrorAction SilentlyContinue - - $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId - } - - It "Test-Json write an error on invalid () Json file against a valid schema from file" -TestCases @( - @{ name = "type"; json = $invalidTypeInJsonPath; errorId = "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } - @{ name = "node"; json = $invalidNodeInJsonPath; errorId = "InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand" } - ) { - param ($json, $errorId) - - $errorVar = $null - Test-Json -Path $json -SchemaFile $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue - - $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId - } - It "Test-Json return all errors when check invalid Json against a valid schema from string" { $errorVar = $null Test-Json -Json $invalidTypeInJson2 -Schema $validSchemaJson -ErrorVariable errorVar -ErrorAction SilentlyContinue @@ -268,26 +153,6 @@ Describe "Test-Json" -Tags "CI" { $errorVar[1].FullyQualifiedErrorId | Should -BeExactly "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } - It "Test-Json return all errors when check invalid Json file against a valid schema from string" { - $errorVar = $null - Test-Json -Path $invalidTypeInJson2Path -Schema $validSchemaJson -ErrorVariable errorVar -ErrorAction SilentlyContinue - - # '$invalidTypeInJson2Path' contains two errors in property types. - $errorVar.Count | Should -Be 2 - $errorVar[0].FullyQualifiedErrorId | Should -BeExactly "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - $errorVar[1].FullyQualifiedErrorId | Should -BeExactly "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - } - - It "Test-Json return all errors when check invalid Json file against a valid schema from file" { - $errorVar = $null - Test-Json -Path $invalidTypeInJson2Path -SchemaFile $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue - - # '$invalidTypeInJson2Path' contains two errors in property types. - $errorVar.Count | Should -Be 2 - $errorVar[0].FullyQualifiedErrorId | Should -BeExactly "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - $errorVar[1].FullyQualifiedErrorId | Should -BeExactly "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" - } - It 'Test-Json recognizes non-object types: ' -TestCases @( @{ name = 'number'; value = 1; expected = 'number' } @{ name = '"true"'; value = '"true"'; expected = 'string' } From 95241e82734b9e28188e2d2d148f4d5b56c36b07 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 6 Sep 2022 12:06:54 +1200 Subject: [PATCH 03/58] adjust brace spacing to match examples in other commands --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 242a4595c30..5cbea7173d3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -145,7 +145,7 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions{OutputFormat = OutputFormat.Basic}); + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic } ); result = validationResults.IsValid; if (validationResults.NestedResults.Count != 0) { From 61f2dbd235953b65dfad05db38393c440eb01821 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 6 Sep 2022 12:08:15 +1200 Subject: [PATCH 04/58] remove space between closing curly brace and closing parenthesis --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 5cbea7173d3..af4db19ef76 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -145,7 +145,7 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic } ); + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; if (validationResults.NestedResults.Count != 0) { From 135f06a6f5c4fa8f095e302db24977a138e1162b Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 8 Sep 2022 09:08:28 +1200 Subject: [PATCH 05/58] configure for automatic downloads of external schemas --- .../commands/utility/TestJsonCommand.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index af4db19ef76..749af8dc486 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -6,9 +6,11 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Net.Http; using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; +using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; @@ -78,6 +80,27 @@ private static bool UnwrapException(Exception e) /// protected override void BeginProcessing() { + SchemaRegistry.Global.Fetch = uri => + { + string text; + switch (uri.Scheme) + { + case "http": + case "https": + text = new HttpClient().GetStringAsync(uri).Result; + break; + case "file": + var filename = Uri.UnescapeDataString(uri.AbsolutePath); + text = File.ReadAllText(filename); + break; + default: + throw new FormatException( + $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + } + + return JsonSerializer.Deserialize(text); + }; + string resolvedpath = string.Empty; try From 42592b5d78601697f7db108987a8b1615326fb52 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 8 Sep 2022 09:11:19 +1200 Subject: [PATCH 06/58] use single quote strings when writing literal JSON values --- .../Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d2e3c52da6b..99e76d4068b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -172,7 +172,7 @@ Describe "Test-Json" -Tags "CI" { # Exactly one type should match $types = 'string', 'number', 'boolean', 'null', 'array', 'object' $types | Where-Object { - $schema = "{ 'type': '$_' }" + $schema = '{ "type": "$_" }' Test-Json -Json $value -Schema $schema -ErrorAction SilentlyContinue } | Should -Be $expected } From ae5b85e4e9f62a70ca3feef3c2e13df786009d45 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 8 Sep 2022 09:36:46 +0500 Subject: [PATCH 07/58] Update test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 --- .../Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 99e76d4068b..fa807ce1547 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -172,7 +172,7 @@ Describe "Test-Json" -Tags "CI" { # Exactly one type should match $types = 'string', 'number', 'boolean', 'null', 'array', 'object' $types | Where-Object { - $schema = '{ "type": "$_" }' + $schema = "{ `"type`": `"$_`" }" Test-Json -Json $value -Schema $schema -ErrorAction SilentlyContinue } | Should -Be $expected } From 0fb4eb1cb6797fcafd5ba4a471ae0000850f89ea Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 09:54:53 +1200 Subject: [PATCH 08/58] detect validation failures and report errors better --- .../commands/utility/TestJsonCommand.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 749af8dc486..6854169c641 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -170,17 +170,30 @@ protected override void ProcessRecord() { var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; - if (validationResults.NestedResults.Count != 0) + if (!result) { Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + if (validationResults.Message != null) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", + ErrorCategory.InvalidData, null); + var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); } + + if (validationResults.HasNestedResults) + { + foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + { + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", + ErrorCategory.InvalidData, null); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); + WriteError(errorRecord); + } + } } } } From 6e332ebcc723de8ba076101bf45c541279883acf Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 17:58:07 +1200 Subject: [PATCH 09/58] capture deserialization exception and record as failure to read ref'd schema --- .../commands/utility/TestJsonCommand.cs | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 6854169c641..9b5fa5ecbe6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -168,33 +168,47 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); - result = validationResults.IsValid; - if (!result) + try { - Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - - if (validationResults.Message != null) + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); + result = validationResults.IsValid; + if (!result) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", - ErrorCategory.InvalidData, null); - var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); - WriteError(errorRecord); - } + Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - if (validationResults.HasNestedResults) - { - foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + if (validationResults.Message != null) { ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); } + + if (validationResults.HasNestedResults) + { + foreach (var nestedResult in validationResults.NestedResults) + { + if (nestedResult.Message == null) + { + continue; + } + + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); + WriteError(errorRecord); + } + } } } + catch (JsonException jsonExc) + { + result = false; + + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + } } } catch (Exception exc) From ed4cdf0837b505ae9b09da2cd0efbbbc719e4331 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 20:33:13 +1200 Subject: [PATCH 10/58] remove component ids for pdb files from .wxs file --- .../commands/utility/TestJsonCommand.cs | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 9b5fa5ecbe6..7ce4e9d92fa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -54,27 +54,6 @@ public class TestJsonCommand : PSCmdlet private JsonSchema _jschema; - /// - /// Process all exceptions in the AggregateException. - /// Unwrap TargetInvocationException if any and - /// rethrow inner exception without losing the stack trace. - /// - /// AggregateException to be unwrapped. - /// Return value is unreachable since we always rethrow. - private static bool UnwrapException(Exception e) - { - if (e.InnerException != null && e is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(e.InnerException).Throw(); - } - else - { - ExceptionDispatchInfo.Capture(e).Throw(); - } - - return true; - } - /// /// Prepare a JSON schema. /// @@ -111,11 +90,9 @@ protected override void BeginProcessing() { _jschema = JsonSchema.FromText(Schema); } - catch (AggregateException ae) + catch (JsonException e) { - // Even if only one exception is thrown, it is still wrapped in an AggregateException exception - // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library - ae.Handle(UnwrapException); + ExceptionDispatchInfo.Capture(e).Throw(); } } else if (SchemaFile != null) @@ -125,9 +102,9 @@ protected override void BeginProcessing() resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFile(resolvedpath); } - catch (AggregateException ae) + catch (JsonException e) { - ae.Handle(UnwrapException); + ExceptionDispatchInfo.Capture(e).Throw(); } } } From beb23b7b93423d6a70582be561f1f840961619bc Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sat, 10 Sep 2022 20:57:57 +1200 Subject: [PATCH 11/58] remove unused usings; add comment regarding json exception during validation --- .../commands/utility/TestJsonCommand.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 7ce4e9d92fa..adbb24aea68 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -4,10 +4,8 @@ using System; using System.Globalization; using System.IO; -using System.Linq; using System.Management.Automation; using System.Net.Http; -using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; using System.Text.Json; @@ -179,6 +177,9 @@ protected override void ProcessRecord() } } } + // A JsonException that occurs during validation is the result of a failure to deserialize + // a referenced schema (through $ref or $dynamicRef). References are resolved at validation + // time and deserialized on-demand. catch (JsonException jsonExc) { result = false; From a571f08cae2362cf339c87e8930d25f4c99e6902 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:15:21 +1200 Subject: [PATCH 12/58] add schema resolution exception; wrap fetch exceptions in new exception and handle --- .../JsonSchemaReferenceResolutionException.cs | 22 +++++++ .../commands/utility/TestJsonCommand.cs | 57 ++++++++++--------- 2 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs new file mode 100644 index 00000000000..ebb487187c9 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; + +namespace Microsoft.PowerShell.Commands; + +internal class JsonSchemaReferenceResolutionException : Exception +{ + /// + /// Thrown during evaluation of when an attempt + /// to resolve a $ref or $dynamicRef fails. + /// + /// + /// The exception that is the cause of the current exception, or a null reference + /// (Nothing in Visual Basic) if no inner exception is specified. + /// + public JsonSchemaReferenceResolutionException(Exception innerException) + : base("An error occurred attempting to resolve a schema reference", innerException) + { + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index adbb24aea68..a313a236573 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -59,23 +59,30 @@ protected override void BeginProcessing() { SchemaRegistry.Global.Fetch = uri => { - string text; - switch (uri.Scheme) + try { - case "http": - case "https": - text = new HttpClient().GetStringAsync(uri).Result; - break; - case "file": - var filename = Uri.UnescapeDataString(uri.AbsolutePath); - text = File.ReadAllText(filename); - break; - default: - throw new FormatException( - $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); - } + string text; + switch (uri.Scheme) + { + case "http": + case "https": + text = new HttpClient().GetStringAsync(uri).Result; + break; + case "file": + var filename = Uri.UnescapeDataString(uri.AbsolutePath); + text = File.ReadAllText(filename); + break; + default: + throw new FormatException( + $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + } - return JsonSerializer.Deserialize(text); + return JsonSerializer.Deserialize(text); + } + catch (Exception e) + { + throw new JsonSchemaReferenceResolutionException(e); + } }; string resolvedpath = string.Empty; @@ -143,8 +150,6 @@ protected override void ProcessRecord() if (_jschema != null) { - try - { var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; if (!result) @@ -176,19 +181,15 @@ protected override void ProcessRecord() } } } - } - // A JsonException that occurs during validation is the result of a failure to deserialize - // a referenced schema (through $ref or $dynamicRef). References are resolved at validation - // time and deserialized on-demand. - catch (JsonException jsonExc) - { - result = false; - - Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); - } } } + catch (JsonSchemaReferenceResolutionException jsonExc) + { + result = false; + + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + } catch (Exception exc) { result = false; From 115919e9205abcb649d2b2ba49a16dcf8a66d4b5 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:17:56 +1200 Subject: [PATCH 13/58] use WriteError instead of throwing exception --- .../commands/utility/TestJsonCommand.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index a313a236573..3e50b01d692 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -97,7 +97,8 @@ protected override void BeginProcessing() } catch (JsonException e) { - ExceptionDispatchInfo.Capture(e).Throw(); + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Schema)); } } else if (SchemaFile != null) @@ -109,7 +110,8 @@ protected override void BeginProcessing() } catch (JsonException e) { - ExceptionDispatchInfo.Capture(e).Throw(); + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile)); } } } @@ -188,7 +190,7 @@ protected override void ProcessRecord() result = false; Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema)); } catch (Exception exc) { From 42381a3944d09c97c1684aeb45756898fc52ccff Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:22:02 +1200 Subject: [PATCH 14/58] fix xml comments --- .../utility/JsonSchemaReferenceResolutionException.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index ebb487187c9..2bbc9deaa4b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -5,11 +5,14 @@ namespace Microsoft.PowerShell.Commands; +/// +/// Thrown during evaluation of when an attempt +/// to resolve a $ref or $dynamicRef fails. +/// internal class JsonSchemaReferenceResolutionException : Exception { /// - /// Thrown during evaluation of when an attempt - /// to resolve a $ref or $dynamicRef fails. + /// Initializes a new instance of the class. /// /// /// The exception that is the cause of the current exception, or a null reference From 0d1cca70eb2df9f651bbf563c86225e132948484 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:06:43 +1200 Subject: [PATCH 15/58] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs Co-authored-by: Ilya --- .../commands/utility/JsonSchemaReferenceResolutionException.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index 2bbc9deaa4b..7699218bbde 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -19,7 +19,7 @@ internal class JsonSchemaReferenceResolutionException : Exception /// (Nothing in Visual Basic) if no inner exception is specified. /// public JsonSchemaReferenceResolutionException(Exception innerException) - : base("An error occurred attempting to resolve a schema reference", innerException) + : base(message: null, innerException) { } } From 3e793607f0edef700447a43dddf4302e8f0a6eb9 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:07:01 +1200 Subject: [PATCH 16/58] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs Co-authored-by: Ilya --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 3e50b01d692..d59973075c9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -57,7 +57,7 @@ public class TestJsonCommand : PSCmdlet /// protected override void BeginProcessing() { - SchemaRegistry.Global.Fetch = uri => + SchemaRegistry.Global.Fetch = static uri => { try { From 8719102df42ff9b810269c8ce8ffbfe867343dfe Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:09:22 +1200 Subject: [PATCH 17/58] use single-line method call; remove unused usings --- .../commands/utility/TestJsonCommand.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index d59973075c9..e08a5c52649 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -6,7 +6,6 @@ using System.IO; using System.Management.Automation; using System.Net.Http; -using System.Runtime.ExceptionServices; using System.Security; using System.Text.Json; using System.Text.Json.Nodes; @@ -160,8 +159,7 @@ protected override void ProcessRecord() if (validationResults.Message != null) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", - ErrorCategory.InvalidData, null); + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); From ae3eb4dc5df6a192e33371c66051c0aba0079309 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sun, 18 Sep 2022 08:50:53 +1200 Subject: [PATCH 18/58] enable nullable refs in JsonSchemaReferenceResolutionException.cs Co-authored-by: Ilya --- .../commands/utility/JsonSchemaReferenceResolutionException.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index 7699218bbde..ba664ccef1b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + using System; namespace Microsoft.PowerShell.Commands; From cbc0d0bd89d6a5bb0680543a086d55c5a355d058 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 6 Oct 2022 08:57:51 +1300 Subject: [PATCH 19/58] move error string to resource file --- .../commands/utility/TestJsonCommand.cs | 3 +- .../resources/TestJsonCmdletStrings.resx | 63 ++++++++++--------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index e08a5c52649..3b644a85615 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -72,8 +72,7 @@ protected override void BeginProcessing() text = File.ReadAllText(filename); break; default: - throw new FormatException( - $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme)); } return JsonSerializer.Deserialize(text); diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index ab105e47fd3..5fdc7a56d22 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -1,17 +1,17 @@ - - - + + @@ -129,4 +129,7 @@ Can not open JSON schema file: {0} - + + URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed. + + \ No newline at end of file From ec7b35e4d1433210ffa703d0f41f95de3a86cb13 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 7 Feb 2023 10:22:56 +1300 Subject: [PATCH 20/58] updated message construction to use resources for localization support --- .../commands/utility/TestJsonCommand.cs | 6 ++---- .../resources/TestJsonCmdletStrings.resx | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 3b644a85615..5b54357086d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -159,8 +159,7 @@ protected override void ProcessRecord() if (validationResults.Message != null) { ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); + errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", validationResults.Message, validationResults.InstanceLocation); WriteError(errorRecord); } @@ -174,8 +173,7 @@ protected override void ProcessRecord() } ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); + errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", nestedResult.Message, nestedResult.InstanceLocation); WriteError(errorRecord); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index 5fdc7a56d22..7850c65dc41 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -124,7 +124,7 @@ Cannot parse the JSON. - The JSON is not valid with the schema. + The JSON is not valid with the schema: {0} at {1} Can not open JSON schema file: {0} @@ -132,4 +132,4 @@ URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed. - \ No newline at end of file + From 3b9bd80ec06d036cdbfd9ba7672dc95bf3abf9f2 Mon Sep 17 00:00:00 2001 From: Ilya Date: Tue, 22 Nov 2022 10:21:25 +0500 Subject: [PATCH 21/58] Replace DllImport with LibraryImport in SMA 5 (#18580) Remove unused code. From 9c43f512f126eac4bcf875c0ac13cbd7fd5f0144 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sun, 4 Sep 2022 09:23:52 +1200 Subject: [PATCH 22/58] updated Test-Json cmdlet to use JsonSchema.Net instead of NJsonSchema --- .../commands/utility/TestJsonCommand.cs | 108 +++++++----------- 1 file changed, 41 insertions(+), 67 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 5b54357086d..242a4595c30 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -4,10 +4,11 @@ using System; using System.Globalization; using System.IO; +using System.Linq; using System.Management.Automation; -using System.Net.Http; +using System.Reflection; +using System.Runtime.ExceptionServices; using System.Security; -using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; @@ -52,37 +53,31 @@ public class TestJsonCommand : PSCmdlet private JsonSchema _jschema; /// - /// Prepare a JSON schema. + /// Process all exceptions in the AggregateException. + /// Unwrap TargetInvocationException if any and + /// rethrow inner exception without losing the stack trace. /// - protected override void BeginProcessing() + /// AggregateException to be unwrapped. + /// Return value is unreachable since we always rethrow. + private static bool UnwrapException(Exception e) { - SchemaRegistry.Global.Fetch = static uri => + if (e.InnerException != null && e is TargetInvocationException) { - try - { - string text; - switch (uri.Scheme) - { - case "http": - case "https": - text = new HttpClient().GetStringAsync(uri).Result; - break; - case "file": - var filename = Uri.UnescapeDataString(uri.AbsolutePath); - text = File.ReadAllText(filename); - break; - default: - throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme)); - } + ExceptionDispatchInfo.Capture(e.InnerException).Throw(); + } + else + { + ExceptionDispatchInfo.Capture(e).Throw(); + } - return JsonSerializer.Deserialize(text); - } - catch (Exception e) - { - throw new JsonSchemaReferenceResolutionException(e); - } - }; + return true; + } + /// + /// Prepare a JSON schema. + /// + protected override void BeginProcessing() + { string resolvedpath = string.Empty; try @@ -93,10 +88,11 @@ protected override void BeginProcessing() { _jschema = JsonSchema.FromText(Schema); } - catch (JsonException e) + catch (AggregateException ae) { - Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Schema)); + // Even if only one exception is thrown, it is still wrapped in an AggregateException exception + // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library + ae.Handle(UnwrapException); } } else if (SchemaFile != null) @@ -106,10 +102,9 @@ protected override void BeginProcessing() resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFile(resolvedpath); } - catch (JsonException e) + catch (AggregateException ae) { - Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile)); + ae.Handle(UnwrapException); } } } @@ -150,43 +145,22 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); - result = validationResults.IsValid; - if (!result) + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions{OutputFormat = OutputFormat.Basic}); + result = validationResults.IsValid; + if (validationResults.NestedResults.Count != 0) + { + Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); + + foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) { - Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - - if (validationResults.Message != null) - { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", validationResults.Message, validationResults.InstanceLocation); - WriteError(errorRecord); - } - - if (validationResults.HasNestedResults) - { - foreach (var nestedResult in validationResults.NestedResults) - { - if (nestedResult.Message == null) - { - continue; - } - - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", nestedResult.Message, nestedResult.InstanceLocation); - WriteError(errorRecord); - } - } + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); + WriteError(errorRecord); } + } } } - catch (JsonSchemaReferenceResolutionException jsonExc) - { - result = false; - - Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema)); - } catch (Exception exc) { result = false; From b1f3d6afb3a08f8d0f211b09b4a7a70e1d9301c5 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 6 Sep 2022 12:06:54 +1200 Subject: [PATCH 23/58] adjust brace spacing to match examples in other commands --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 242a4595c30..5cbea7173d3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -145,7 +145,7 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions{OutputFormat = OutputFormat.Basic}); + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic } ); result = validationResults.IsValid; if (validationResults.NestedResults.Count != 0) { From 26faded0cb757a2dbd4c1e34e76ccbec9be1d298 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 6 Sep 2022 12:08:15 +1200 Subject: [PATCH 24/58] remove space between closing curly brace and closing parenthesis --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 5cbea7173d3..af4db19ef76 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -145,7 +145,7 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic } ); + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; if (validationResults.NestedResults.Count != 0) { From 097b11b11a4c583c4dd65682261b2f32afe192ca Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 8 Sep 2022 09:08:28 +1200 Subject: [PATCH 25/58] configure for automatic downloads of external schemas --- .../commands/utility/TestJsonCommand.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index af4db19ef76..749af8dc486 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -6,9 +6,11 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Net.Http; using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; +using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; @@ -78,6 +80,27 @@ private static bool UnwrapException(Exception e) /// protected override void BeginProcessing() { + SchemaRegistry.Global.Fetch = uri => + { + string text; + switch (uri.Scheme) + { + case "http": + case "https": + text = new HttpClient().GetStringAsync(uri).Result; + break; + case "file": + var filename = Uri.UnescapeDataString(uri.AbsolutePath); + text = File.ReadAllText(filename); + break; + default: + throw new FormatException( + $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + } + + return JsonSerializer.Deserialize(text); + }; + string resolvedpath = string.Empty; try From 8aaef476fd2910e2002a4bee91404b3140c1a131 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 8 Sep 2022 09:11:19 +1200 Subject: [PATCH 26/58] use single quote strings when writing literal JSON values --- .../Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fa807ce1547..99e76d4068b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -172,7 +172,7 @@ Describe "Test-Json" -Tags "CI" { # Exactly one type should match $types = 'string', 'number', 'boolean', 'null', 'array', 'object' $types | Where-Object { - $schema = "{ `"type`": `"$_`" }" + $schema = '{ "type": "$_" }' Test-Json -Json $value -Schema $schema -ErrorAction SilentlyContinue } | Should -Be $expected } From e240b37113314de592f6fb1a55c9fd3659ce1ee4 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 8 Sep 2022 09:36:46 +0500 Subject: [PATCH 27/58] Update test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 --- .../Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 99e76d4068b..fa807ce1547 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -172,7 +172,7 @@ Describe "Test-Json" -Tags "CI" { # Exactly one type should match $types = 'string', 'number', 'boolean', 'null', 'array', 'object' $types | Where-Object { - $schema = '{ "type": "$_" }' + $schema = "{ `"type`": `"$_`" }" Test-Json -Json $value -Schema $schema -ErrorAction SilentlyContinue } | Should -Be $expected } From 639ea31e52de93faab888867e91efd0801e0dd1f Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 09:54:53 +1200 Subject: [PATCH 28/58] detect validation failures and report errors better --- .../commands/utility/TestJsonCommand.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 749af8dc486..6854169c641 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -170,17 +170,30 @@ protected override void ProcessRecord() { var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; - if (validationResults.NestedResults.Count != 0) + if (!result) { Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + if (validationResults.Message != null) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", + ErrorCategory.InvalidData, null); + var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); } + + if (validationResults.HasNestedResults) + { + foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + { + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", + ErrorCategory.InvalidData, null); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); + WriteError(errorRecord); + } + } } } } From 6a385e14ae52565e82fb417e9f1e581bfee88289 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 17:58:07 +1200 Subject: [PATCH 29/58] capture deserialization exception and record as failure to read ref'd schema --- .../commands/utility/TestJsonCommand.cs | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 6854169c641..9b5fa5ecbe6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -168,33 +168,47 @@ protected override void ProcessRecord() if (_jschema != null) { - var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); - result = validationResults.IsValid; - if (!result) + try { - Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - - if (validationResults.Message != null) + var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); + result = validationResults.IsValid; + if (!result) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", - ErrorCategory.InvalidData, null); - var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); - WriteError(errorRecord); - } + Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); - if (validationResults.HasNestedResults) - { - foreach (var nestedResult in validationResults.NestedResults.Where(x => x.Message != null)) + if (validationResults.Message != null) { ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); } + + if (validationResults.HasNestedResults) + { + foreach (var nestedResult in validationResults.NestedResults) + { + if (nestedResult.Message == null) + { + continue; + } + + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); + var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; + errorRecord.ErrorDetails = new ErrorDetails(message); + WriteError(errorRecord); + } + } } } + catch (JsonException jsonExc) + { + result = false; + + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + } } } catch (Exception exc) From db20b2ac96fdb79cdbcbb04f90da89ad9c1e2385 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Fri, 9 Sep 2022 20:33:13 +1200 Subject: [PATCH 30/58] remove component ids for pdb files from .wxs file --- .../commands/utility/TestJsonCommand.cs | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 9b5fa5ecbe6..7ce4e9d92fa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -54,27 +54,6 @@ public class TestJsonCommand : PSCmdlet private JsonSchema _jschema; - /// - /// Process all exceptions in the AggregateException. - /// Unwrap TargetInvocationException if any and - /// rethrow inner exception without losing the stack trace. - /// - /// AggregateException to be unwrapped. - /// Return value is unreachable since we always rethrow. - private static bool UnwrapException(Exception e) - { - if (e.InnerException != null && e is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(e.InnerException).Throw(); - } - else - { - ExceptionDispatchInfo.Capture(e).Throw(); - } - - return true; - } - /// /// Prepare a JSON schema. /// @@ -111,11 +90,9 @@ protected override void BeginProcessing() { _jschema = JsonSchema.FromText(Schema); } - catch (AggregateException ae) + catch (JsonException e) { - // Even if only one exception is thrown, it is still wrapped in an AggregateException exception - // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library - ae.Handle(UnwrapException); + ExceptionDispatchInfo.Capture(e).Throw(); } } else if (SchemaFile != null) @@ -125,9 +102,9 @@ protected override void BeginProcessing() resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFile(resolvedpath); } - catch (AggregateException ae) + catch (JsonException e) { - ae.Handle(UnwrapException); + ExceptionDispatchInfo.Capture(e).Throw(); } } } From 467f0493d39f8437418a88a14fffb1ffa04645e2 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sat, 10 Sep 2022 20:57:57 +1200 Subject: [PATCH 31/58] remove unused usings; add comment regarding json exception during validation --- .../commands/utility/TestJsonCommand.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 7ce4e9d92fa..adbb24aea68 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -4,10 +4,8 @@ using System; using System.Globalization; using System.IO; -using System.Linq; using System.Management.Automation; using System.Net.Http; -using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; using System.Text.Json; @@ -179,6 +177,9 @@ protected override void ProcessRecord() } } } + // A JsonException that occurs during validation is the result of a failure to deserialize + // a referenced schema (through $ref or $dynamicRef). References are resolved at validation + // time and deserialized on-demand. catch (JsonException jsonExc) { result = false; From 51aea5add8dc50f25854f443669e8a269b424533 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:15:21 +1200 Subject: [PATCH 32/58] add schema resolution exception; wrap fetch exceptions in new exception and handle --- .../JsonSchemaReferenceResolutionException.cs | 11 +--- .../commands/utility/TestJsonCommand.cs | 57 ++++++++++--------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index ba664ccef1b..ebb487187c9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -1,27 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#nullable enable - using System; namespace Microsoft.PowerShell.Commands; -/// -/// Thrown during evaluation of when an attempt -/// to resolve a $ref or $dynamicRef fails. -/// internal class JsonSchemaReferenceResolutionException : Exception { /// - /// Initializes a new instance of the class. + /// Thrown during evaluation of when an attempt + /// to resolve a $ref or $dynamicRef fails. /// /// /// The exception that is the cause of the current exception, or a null reference /// (Nothing in Visual Basic) if no inner exception is specified. /// public JsonSchemaReferenceResolutionException(Exception innerException) - : base(message: null, innerException) + : base("An error occurred attempting to resolve a schema reference", innerException) { } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index adbb24aea68..a313a236573 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -59,23 +59,30 @@ protected override void BeginProcessing() { SchemaRegistry.Global.Fetch = uri => { - string text; - switch (uri.Scheme) + try { - case "http": - case "https": - text = new HttpClient().GetStringAsync(uri).Result; - break; - case "file": - var filename = Uri.UnescapeDataString(uri.AbsolutePath); - text = File.ReadAllText(filename); - break; - default: - throw new FormatException( - $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); - } + string text; + switch (uri.Scheme) + { + case "http": + case "https": + text = new HttpClient().GetStringAsync(uri).Result; + break; + case "file": + var filename = Uri.UnescapeDataString(uri.AbsolutePath); + text = File.ReadAllText(filename); + break; + default: + throw new FormatException( + $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + } - return JsonSerializer.Deserialize(text); + return JsonSerializer.Deserialize(text); + } + catch (Exception e) + { + throw new JsonSchemaReferenceResolutionException(e); + } }; string resolvedpath = string.Empty; @@ -143,8 +150,6 @@ protected override void ProcessRecord() if (_jschema != null) { - try - { var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); result = validationResults.IsValid; if (!result) @@ -176,19 +181,15 @@ protected override void ProcessRecord() } } } - } - // A JsonException that occurs during validation is the result of a failure to deserialize - // a referenced schema (through $ref or $dynamicRef). References are resolved at validation - // time and deserialized on-demand. - catch (JsonException jsonExc) - { - result = false; - - Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); - } } } + catch (JsonSchemaReferenceResolutionException jsonExc) + { + result = false; + + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + } catch (Exception exc) { result = false; From 843136b5903e8524bde4b5c03a28007b27a23285 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:17:56 +1200 Subject: [PATCH 33/58] use WriteError instead of throwing exception --- .../commands/utility/TestJsonCommand.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index a313a236573..3e50b01d692 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -97,7 +97,8 @@ protected override void BeginProcessing() } catch (JsonException e) { - ExceptionDispatchInfo.Capture(e).Throw(); + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Schema)); } } else if (SchemaFile != null) @@ -109,7 +110,8 @@ protected override void BeginProcessing() } catch (JsonException e) { - ExceptionDispatchInfo.Capture(e).Throw(); + Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile)); } } } @@ -188,7 +190,7 @@ protected override void ProcessRecord() result = false; Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); - WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Json)); + WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema)); } catch (Exception exc) { From edfc4b68dcdbc318a05b4bfd94bea4ce9d737d02 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 12 Sep 2022 10:22:02 +1200 Subject: [PATCH 34/58] fix xml comments --- .../utility/JsonSchemaReferenceResolutionException.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index ebb487187c9..2bbc9deaa4b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -5,11 +5,14 @@ namespace Microsoft.PowerShell.Commands; +/// +/// Thrown during evaluation of when an attempt +/// to resolve a $ref or $dynamicRef fails. +/// internal class JsonSchemaReferenceResolutionException : Exception { /// - /// Thrown during evaluation of when an attempt - /// to resolve a $ref or $dynamicRef fails. + /// Initializes a new instance of the class. /// /// /// The exception that is the cause of the current exception, or a null reference From df7cc4db04468a17025d1ddd13696d317a42c0dd Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:06:43 +1200 Subject: [PATCH 35/58] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs Co-authored-by: Ilya --- .../commands/utility/JsonSchemaReferenceResolutionException.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index 2bbc9deaa4b..7699218bbde 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -19,7 +19,7 @@ internal class JsonSchemaReferenceResolutionException : Exception /// (Nothing in Visual Basic) if no inner exception is specified. /// public JsonSchemaReferenceResolutionException(Exception innerException) - : base("An error occurred attempting to resolve a schema reference", innerException) + : base(message: null, innerException) { } } From 0cb49d0a49fe83a175f8463eac37ca1f1ccbfc6b Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:07:01 +1200 Subject: [PATCH 36/58] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs Co-authored-by: Ilya --- .../commands/utility/TestJsonCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 3e50b01d692..d59973075c9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -57,7 +57,7 @@ public class TestJsonCommand : PSCmdlet /// protected override void BeginProcessing() { - SchemaRegistry.Global.Fetch = uri => + SchemaRegistry.Global.Fetch = static uri => { try { From 31de5b67300e54ce6c4d0eab1585ea82f3b203f6 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 13 Sep 2022 11:09:22 +1200 Subject: [PATCH 37/58] use single-line method call; remove unused usings --- .../commands/utility/TestJsonCommand.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index d59973075c9..e08a5c52649 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -6,7 +6,6 @@ using System.IO; using System.Management.Automation; using System.Net.Http; -using System.Runtime.ExceptionServices; using System.Security; using System.Text.Json; using System.Text.Json.Nodes; @@ -160,8 +159,7 @@ protected override void ProcessRecord() if (validationResults.Message != null) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", - ErrorCategory.InvalidData, null); + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; errorRecord.ErrorDetails = new ErrorDetails(message); WriteError(errorRecord); From 6214b07bf22b139ae041bd4dd037e202c89250bb Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Sun, 18 Sep 2022 08:50:53 +1200 Subject: [PATCH 38/58] enable nullable refs in JsonSchemaReferenceResolutionException.cs Co-authored-by: Ilya --- .../commands/utility/JsonSchemaReferenceResolutionException.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index 7699218bbde..ba664ccef1b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + using System; namespace Microsoft.PowerShell.Commands; From 5005a3f1c878a84ecbfbb0cc0a3cbbe369d22c55 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 6 Oct 2022 08:57:51 +1300 Subject: [PATCH 39/58] move error string to resource file --- .../commands/utility/TestJsonCommand.cs | 3 +-- .../resources/TestJsonCmdletStrings.resx | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index e08a5c52649..3b644a85615 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -72,8 +72,7 @@ protected override void BeginProcessing() text = File.ReadAllText(filename); break; default: - throw new FormatException( - $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); + throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme)); } return JsonSerializer.Deserialize(text); diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index 7850c65dc41..5fdc7a56d22 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -124,7 +124,7 @@ Cannot parse the JSON. - The JSON is not valid with the schema: {0} at {1} + The JSON is not valid with the schema. Can not open JSON schema file: {0} @@ -132,4 +132,4 @@ URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed. - + \ No newline at end of file From 42f8b70a74dd68d0cb6e403db95f1dbbc3c1c0f6 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Mon, 6 Feb 2023 09:43:48 -0800 Subject: [PATCH 40/58] remove extra whitespace --- .../resources/TestJsonCmdletStrings.resx | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index 5fdc7a56d22..9bf9a9d64f3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -1,17 +1,17 @@ - @@ -132,4 +132,4 @@ URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed. - \ No newline at end of file + From 1ab695787b9e978dee56eeb67c2526482e92fe0b Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Wed, 8 Feb 2023 12:52:48 +1300 Subject: [PATCH 41/58] upated jsonschema.net package version --- .../Microsoft.PowerShell.Commands.Utility.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index c7ad6fb7711..b9bf1bd27b8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -35,7 +35,7 @@ - + From 8380399afc5984b5a709ce065db2a1060c3c84a9 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 9 Feb 2023 12:06:28 +1300 Subject: [PATCH 42/58] add error message without parameters; add comment for fetch method; dispose of http client --- .../commands/utility/TestJsonCommand.cs | 24 ++++--- .../resources/TestJsonCmdletStrings.resx | 63 ++++++++++--------- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 3b644a85615..dd757f27c0c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -56,6 +56,13 @@ public class TestJsonCommand : PSCmdlet /// protected override void BeginProcessing() { + // By default, a JSON Schema implementation isn't supposed to automatically fetch content. + // Instead JsonSchema.Net has been set up with a registry so that users can pre-register + // any schemas they may need to resolve. + // However, pre-registering schemas doesn't make sense in the context of a Powershell command, + // and automatically fetching referenced URIs is likely the preferred behavior. To do that, + // this property must be set with a method to retrieve and deserialize the content. + // For more information, see https://json-everything.net/json-schema#automatic-resolution SchemaRegistry.Global.Fetch = static uri => { try @@ -65,8 +72,11 @@ protected override void BeginProcessing() { case "http": case "https": - text = new HttpClient().GetStringAsync(uri).Result; - break; + { + using var client = new HttpClient(); + text = client.GetStringAsync(uri).Result; + break; + } case "file": var filename = Uri.UnescapeDataString(uri.AbsolutePath); text = File.ReadAllText(filename); @@ -158,9 +168,8 @@ protected override void ProcessRecord() if (validationResults.Message != null) { - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null); + errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", validationResults.Message, validationResults.InstanceLocation); WriteError(errorRecord); } @@ -173,9 +182,8 @@ protected override void ProcessRecord() continue; } - ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); - var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; - errorRecord.ErrorDetails = new ErrorDetails(message); + ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null); + errorRecord.ErrorDetails = new ErrorDetails(typeof(TestJsonCommand).Assembly, "TestJsonCmdletStrings", "InvalidJsonAgainstSchema", nestedResult.Message, nestedResult.InstanceLocation); WriteError(errorRecord); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index 9bf9a9d64f3..c2055103aaa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -1,17 +1,17 @@ - @@ -123,8 +123,8 @@ Cannot parse the JSON. - - The JSON is not valid with the schema. + + The JSON is not valid with the schema: {0} at {1} Can not open JSON schema file: {0} @@ -132,4 +132,7 @@ URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed. - + + The JSON is not valid with the schema. + + \ No newline at end of file From 11380a1d720aeea36f0223c4c6005aad00184e43 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 9 Feb 2023 18:16:38 +1300 Subject: [PATCH 43/58] remove whitespace --- .../resources/TestJsonCmdletStrings.resx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index c2055103aaa..76f7c4ac7a1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -1,17 +1,17 @@ - - - + + From d847444644546de1e0d7baa8ad7ff0be6da9e76b Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Thu, 9 Feb 2023 18:20:47 +1300 Subject: [PATCH 45/58] one last space --- .../resources/TestJsonCmdletStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index f684e713b37..d943225922f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -1,7 +1,7 @@