From 3a6f1fd078d0d661140304d443aee6bc196e3057 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 23 Feb 2020 23:57:23 +0300 Subject: [PATCH 01/28] Add SchemaPath parameter --- .../commands/utility/TestJsonCommand.cs | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 23f0cc7c37f..e08877671e1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -15,9 +15,12 @@ namespace Microsoft.PowerShell.Commands /// /// This class implements Test-Json command. /// - [Cmdlet(VerbsDiagnostic.Test, "Json", HelpUri = "")] + [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "")] public class TestJsonCommand : PSCmdlet { + private const string SchemaPathParameterSet = "SchemaPath"; + private const string SchemaStringParameterSet = "SchemaString"; + /// /// An JSON to be validated. /// @@ -32,10 +35,22 @@ public class TestJsonCommand : PSCmdlet /// 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)] + [Parameter(Position = 1, ParameterSetName = TestJsonCommand.SchemaStringParameterSet)] [ValidateNotNullOrEmpty()] public string Schema { get; set; } + /// + /// A path to the file containg schema to validate the JSON against. + /// This is optional parameter. + /// If the parameter is absent the cmdlet only attempts to parse the JSON string. + /// If the parameter present the cmdlet attempts to parse the JSON string and + /// 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, ParameterSetName = TestJsonCommand.SchemaPathParameterSet)] + [ValidateNotNullOrEmpty()] + public string SchemaPath { get; set; } + private JsonSchema _jschema; /// @@ -43,18 +58,35 @@ public class TestJsonCommand : PSCmdlet /// protected override void BeginProcessing() { - if (Schema != null) + try { - try + if (Schema != null) { _jschema = JsonSchema.FromJsonAsync(Schema).Result; + } - catch (Exception exc) + else if (SchemaPath != null) { - Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, exc); - ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, null)); + string resolvedpath = string.Empty; + + try + { + resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, true); + } + catch (ItemNotFoundException e) + { + // NOTE: This will throw + PathUtils.ReportFileOpenFailure(this, resolvedpath, e); + } + + _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; } } + catch (Exception exc) + { + Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, exc); + ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, null)); + } } /// From 3d5e83421327b5b7fa36ec72c4968fc2711f9d5b Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 23 Feb 2020 23:59:01 +0300 Subject: [PATCH 02/28] Remove unnecessary usings --- .../commands/utility/TestJsonCommand.cs | 3 --- 1 file changed, 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 e08877671e1..9d200853d90 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -2,11 +2,8 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Management.Automation; -using System.Management.Automation.Internal; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NJsonSchema; From 576866b579d77b5ee785ab32203a9f5bb912ea94 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Mon, 24 Feb 2020 19:30:48 +0300 Subject: [PATCH 03/28] Add tests --- .../Test-Json.Tests.ps1 | 61 ++++++++++++++++--- .../assets/invalid_schema_definitions.json | 8 +++ .../assets/invalid_schema_reference.json | 12 ++++ .../assets/valid_schema_definitions.json | 13 ++++ .../assets/valid_schema_reference.json | 12 ++++ 5 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json 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 cf5a9438406..76816fd99ad 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -3,6 +3,12 @@ Describe "Test-Json" -Tags "CI" { BeforeAll { + # JSON schema referencing valid definitions + $validSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath valid_schema_reference.json + + # JSON schema referencing invalid definitions + $invalidSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath invalid_schema_reference.json + $validSchemaJson = @" { 'description': 'A person', @@ -65,36 +71,61 @@ Describe "Test-Json" -Tags "CI" { Test-Json -Json $validJson | Should -BeTrue } - It "Json is valid against a valid schema" { + It "Json is valid against a valid schema from string" { Test-Json -Json $validJson -Schema $validSchemaJson | Should -BeTrue } + It "Json is valid against a valid schema from file" { + Test-Json -Json $validJson -SchemaPath $validSchemaJsonPath | Should -BeTrue + } + It "Json is invalid" { Test-Json -Json $invalidNodeInJson -ErrorAction SilentlyContinue | Should -BeFalse } - It "Json is invalid against a valid schema" { + It "Json is invalid against a valid schema from string" { Test-Json -Json $invalidTypeInJson2 -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse Test-Json -Json $invalidNodeInJson -Schema $validSchemaJson -ErrorAction SilentlyContinue | Should -BeFalse } - It "Test-Json throw if a schema is invalid" { + It "Json is invalid against a valid schema from file" { + Test-Json -Json $invalidTypeInJson2 -SchemaPath $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse + Test-Json -Json $invalidNodeInJson -SchemaPath $validSchemaJsonPath -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" } - It "Test-Json write an error on invalid () Json against a valid schema" -TestCases @( + It "Test-Json throw if a schema from file is invalid" { + { Test-Json -Json $validJson -SchemaPath $invalidSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" + } + + It "Test-Json write an error on invalid () Json against a valid schema from string" -TestCases @( + @{ name = "type"; json = $invalidTypeInJson; errorId = "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } + @{ name = "node"; json = $invalidNodeInJson; errorId = "InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand" } + ) { + param ($json, $errorId) + + $errorVar = $null + Test-Json -Json $json -Schema $validSchemaJson -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId + } + + It "Test-Json write an error on invalid () Json against a valid schema from file" -TestCases @( @{ name = "type"; json = $invalidTypeInJson; errorId = "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } @{ name = "node"; json = $invalidNodeInJson; errorId = "InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand" } - ) { - param ($json, $errorId) + ) { + param ($json, $errorId) - $errorVar = $null - Test-Json -Json $json -Schema $validSchemaJson -ErrorVariable errorVar -ErrorAction SilentlyContinue + $errorVar = $null + Test-Json -Json $json -SchemaPath $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue - $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId + $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId } - It "Test-Json return all errors when check invalid Json against a valid schema" { + 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 @@ -103,4 +134,14 @@ Describe "Test-Json" -Tags "CI" { $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 against a valid schema from file" { + $errorVar = $null + Test-Json -Json $invalidTypeInJson2 -SchemaPath $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue + + # '$invalidTypeInJson2' 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" + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json new file mode 100644 index 00000000000..a2b48e794b2 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json @@ -0,0 +1,8 @@ +{ + "definitions": { + "name": { + "type": "string" + }, + "hobbies" + } +} \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json new file mode 100644 index 00000000000..47609b3f4d1 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json @@ -0,0 +1,12 @@ +{ + "description": "A person", + "type": "object", + "properties": { + "name": { + "$ref": "invalid_schema_definitions.json#/definitions/name" + }, + "hobbies": { + "$ref": "invalid_schema_definitions.json#/definitions/hobbies" + } + } +} \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json new file mode 100644 index 00000000000..bf5c89363e2 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json @@ -0,0 +1,13 @@ +{ + "definitions": { + "name": { + "type": "string" + }, + "hobbies": { + "type": "array", + "items": { + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json new file mode 100644 index 00000000000..adbdb4b45de --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json @@ -0,0 +1,12 @@ +{ + "description": "A person", + "type": "object", + "properties": { + "name": { + "$ref": "valid_schema_definitions.json#/definitions/name" + }, + "hobbies": { + "$ref": "valid_schema_definitions.json#/definitions/hobbies" + } + } +} \ No newline at end of file From 0b27f48b203c44345711c13fe7210fd85daee44c Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 25 Feb 2020 00:19:22 +0300 Subject: [PATCH 04/28] Add newline at the EOF --- .../assets/invalid_schema_definitions.json | 2 +- .../assets/invalid_schema_reference.json | 2 +- .../assets/valid_schema_definitions.json | 2 +- .../assets/valid_schema_reference.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json index a2b48e794b2..d3fc0cdeef9 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_definitions.json @@ -5,4 +5,4 @@ }, "hobbies" } -} \ No newline at end of file +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json index 47609b3f4d1..32520f59496 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/invalid_schema_reference.json @@ -9,4 +9,4 @@ "$ref": "invalid_schema_definitions.json#/definitions/hobbies" } } -} \ No newline at end of file +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json index bf5c89363e2..5396927a5bf 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_definitions.json @@ -10,4 +10,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json index adbdb4b45de..aa9c18a30c7 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/valid_schema_reference.json @@ -9,4 +9,4 @@ "$ref": "valid_schema_definitions.json#/definitions/hobbies" } } -} \ No newline at end of file +} From f07bec060304965bf5f18418cfceaeba819c08b1 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 25 Feb 2020 00:36:10 +0300 Subject: [PATCH 05/28] Use named argument for 'ResolveFilePath' 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 9d200853d90..75d963fb87d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -68,7 +68,7 @@ protected override void BeginProcessing() try { - resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, true); + resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, isLiteralPath: true); } catch (ItemNotFoundException e) { From 8b4f4d5b1462bad82615e5def340f9bc73a6e11e Mon Sep 17 00:00:00 2001 From: beatcracker Date: Thu, 27 Feb 2020 01:15:30 +0300 Subject: [PATCH 06/28] Remove "ReportFileOpenFailure" usage Seems that "ResolveFilePath" doesn't throw in any conditions I could test. NJsonSchema will throw "System.IO.IOException" so we catch that. --- .../commands/utility/TestJsonCommand.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 75d963fb87d..e6d46e1ff9a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -65,16 +65,7 @@ protected override void BeginProcessing() else if (SchemaPath != null) { string resolvedpath = string.Empty; - - try - { - resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, isLiteralPath: true); - } - catch (ItemNotFoundException e) - { - // NOTE: This will throw - PathUtils.ReportFileOpenFailure(this, resolvedpath, e); - } + resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, isLiteralPath: true); _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; } From 1e991d224e4f34e05383d892ce4131e8969b3196 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 1 Mar 2020 22:22:46 +0300 Subject: [PATCH 07/28] Handle AggregateException from async methods --- .../commands/utility/TestJsonCommand.cs | 76 +++++++++++++++++-- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index e6d46e1ff9a..74a38aab055 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -2,6 +2,10 @@ // Licensed under the MIT License. using System; +using System.Runtime.ExceptionServices; +using System.Reflection; +using System.Security; +using System.IO; using System.Management.Automation; using Newtonsoft.Json.Linq; @@ -55,24 +59,80 @@ public class TestJsonCommand : PSCmdlet /// protected override void BeginProcessing() { + string resolvedpath = string.Empty; + try { if (Schema != null) { - _jschema = JsonSchema.FromJsonAsync(Schema).Result; - + try + { + _jschema = JsonSchema.FromJsonAsync(Schema).Result; + } + // 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 + catch (AggregateException ae) + { + // Process all exceptions in the AggregateException + ae.Handle(i => + { + // Unwrap TargetInvocationException if any + // Rethrow inner exception without losing the stack trace + if (i is TargetInvocationException) + { + ExceptionDispatchInfo.Capture(i.InnerException).Throw(); + } + else + { + ExceptionDispatchInfo.Capture(i).Throw(); + } + return true; + } + ); + } } else if (SchemaPath != null) { - string resolvedpath = string.Empty; - resolvedpath = PathUtils.ResolveFilePath(SchemaPath, this, isLiteralPath: true); - - _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; + try + { + resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaPath); + _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; + } + catch (AggregateException ae) + { + ae.Handle(i => + { + if (i is TargetInvocationException) + { + ExceptionDispatchInfo.Capture(i.InnerException).Throw(); + } + else + { + ExceptionDispatchInfo.Capture(i).Throw(); + } + return true; + } + ); + } } } - catch (Exception exc) + // Handle exceptions related to file access to provide more specific error message + // https://docs.microsoft.com/en-us/dotnet/standard/io/handling-io-errors + catch (Exception e) when ( + e is IOException || + e is UnauthorizedAccessException || + e is NotSupportedException || + e is SecurityException + ) + { + // Do we really need to wrap exception? Not doing this provides more clear error message upfront. + // E.g.: "'{}'|Test-Json -SchemaPath c:" results in "Test-Json : Access to the path 'C:\' is denied". + Exception exception = new Exception("JSON schema file open failure", e); // TODO: Add resource string + ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); + } + catch (Exception e) { - Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, exc); + Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, e); ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, null)); } } From 5a183bc1b982e45316642a172faed57042d41e1a Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 1 Mar 2020 22:24:54 +0300 Subject: [PATCH 08/28] Add tests for JSON schema file open failure --- .../Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 76816fd99ad..24ec58cb1b2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -9,6 +9,9 @@ Describe "Test-Json" -Tags "CI" { # JSON schema referencing invalid definitions $invalidSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath invalid_schema_reference.json + # JSON schema file that doesn't exist + $missingSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath no_such_file.json + $validSchemaJson = @" { 'description': 'A person', @@ -67,6 +70,10 @@ Describe "Test-Json" -Tags "CI" { "@ } + It "Missing JSON schema file doesn't exist" { + Test-Path -LiteralPath $missingSchemaJsonPath | Should -BeFalse + } + It "Json is valid" { Test-Json -Json $validJson | Should -BeTrue } @@ -101,6 +108,10 @@ Describe "Test-Json" -Tags "CI" { { Test-Json -Json $validJson -SchemaPath $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 -SchemaPath $missingSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "JsonSchemaFileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" + } + It "Test-Json write an error on invalid () Json against a valid schema from string" -TestCases @( @{ name = "type"; json = $invalidTypeInJson; errorId = "InvalidJsonAgainstSchema,Microsoft.PowerShell.Commands.TestJsonCommand" } @{ name = "node"; json = $invalidNodeInJson; errorId = "InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand" } From 77a24affe9efb1ab5c2507b28ce4ed88415d8c28 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 1 Mar 2020 23:59:22 +0300 Subject: [PATCH 09/28] Replace "An JSON" with "A JSON" --- .../commands/utility/TestJsonCommand.cs | 6 +++--- 1 file changed, 3 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 74a38aab055..5a23b6b40ea 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -23,7 +23,7 @@ public class TestJsonCommand : PSCmdlet private const string SchemaStringParameterSet = "SchemaString"; /// - /// An JSON to be validated. + /// A JSON to be validated. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] public string Json { get; set; } @@ -55,7 +55,7 @@ public class TestJsonCommand : PSCmdlet private JsonSchema _jschema; /// - /// Prepare an JSON schema. + /// Prepare a JSON schema. /// protected override void BeginProcessing() { @@ -138,7 +138,7 @@ e is SecurityException } /// - /// Validate an JSON. + /// Validate a JSON. /// protected override void ProcessRecord() { From c86c47d6902bf1bda17d1c9bf2ae85569bf62e49 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Mon, 2 Mar 2020 00:03:21 +0300 Subject: [PATCH 10/28] Replace "A JSON" with "A JSON string" --- .../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 5a23b6b40ea..4fb639f5293 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -23,7 +23,7 @@ public class TestJsonCommand : PSCmdlet private const string SchemaStringParameterSet = "SchemaString"; /// - /// A JSON to be validated. + /// A JSON string to be validated. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] public string Json { get; set; } From 5b5ef806734fc92e5c11638af038c06ae80b109d Mon Sep 17 00:00:00 2001 From: beatcracker Date: Mon, 2 Mar 2020 22:52:28 +0300 Subject: [PATCH 11/28] Replace "SchemaPath" with "SchemaFile" --- .../commands/utility/TestJsonCommand.cs | 12 ++++++------ .../Test-Json.Tests.ps1 | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 4fb639f5293..ddd69bd6eb7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -19,7 +19,7 @@ namespace Microsoft.PowerShell.Commands [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "")] public class TestJsonCommand : PSCmdlet { - private const string SchemaPathParameterSet = "SchemaPath"; + private const string SchemaFileParameterSet = "SchemaFile"; private const string SchemaStringParameterSet = "SchemaString"; /// @@ -48,9 +48,9 @@ public class TestJsonCommand : PSCmdlet /// 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, ParameterSetName = TestJsonCommand.SchemaPathParameterSet)] + [Parameter(Position = 1, ParameterSetName = TestJsonCommand.SchemaFileParameterSet)] [ValidateNotNullOrEmpty()] - public string SchemaPath { get; set; } + public string SchemaFile { get; set; } private JsonSchema _jschema; @@ -91,11 +91,11 @@ protected override void BeginProcessing() ); } } - else if (SchemaPath != null) + else if (SchemaFile != null) { try { - resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaPath); + resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; } catch (AggregateException ae) @@ -126,7 +126,7 @@ e is SecurityException ) { // Do we really need to wrap exception? Not doing this provides more clear error message upfront. - // E.g.: "'{}'|Test-Json -SchemaPath c:" results in "Test-Json : Access to the path 'C:\' is denied". + // E.g.: "'{}'|Test-Json -SchemaFile c:" results in "Test-Json : Access to the path 'C:\' is denied". Exception exception = new Exception("JSON schema file open failure", e); // TODO: Add resource string ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); } 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 24ec58cb1b2..d14cbf4c785 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -83,7 +83,7 @@ Describe "Test-Json" -Tags "CI" { } It "Json is valid against a valid schema from file" { - Test-Json -Json $validJson -SchemaPath $validSchemaJsonPath | Should -BeTrue + Test-Json -Json $validJson -SchemaFile $validSchemaJsonPath | Should -BeTrue } It "Json is invalid" { @@ -96,8 +96,8 @@ Describe "Test-Json" -Tags "CI" { } It "Json is invalid against a valid schema from file" { - Test-Json -Json $invalidTypeInJson2 -SchemaPath $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse - Test-Json -Json $invalidNodeInJson -SchemaPath $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse + Test-Json -Json $invalidTypeInJson2 -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse + Test-Json -Json $invalidNodeInJson -SchemaFile $validSchemaJsonPath -ErrorAction SilentlyContinue | Should -BeFalse } It "Test-Json throw if a schema from string is invalid" { @@ -105,11 +105,11 @@ Describe "Test-Json" -Tags "CI" { } It "Test-Json throw if a schema from file is invalid" { - { Test-Json -Json $validJson -SchemaPath $invalidSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "InvalidJsonSchema,Microsoft.PowerShell.Commands.TestJsonCommand" + { Test-Json -Json $validJson -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 -SchemaPath $missingSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "JsonSchemaFileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" + { Test-Json -Json $validJson -SchemaFile $missingSchemaJsonPath -ErrorAction Stop } | Should -Throw -ErrorId "JsonSchemaFileOpenFailure,Microsoft.PowerShell.Commands.TestJsonCommand" } It "Test-Json write an error on invalid () Json against a valid schema from string" -TestCases @( @@ -131,7 +131,7 @@ Describe "Test-Json" -Tags "CI" { param ($json, $errorId) $errorVar = $null - Test-Json -Json $json -SchemaPath $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue + Test-Json -Json $json -SchemaFile $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue $errorVar.FullyQualifiedErrorId | Should -BeExactly $errorId } @@ -148,7 +148,7 @@ Describe "Test-Json" -Tags "CI" { It "Test-Json return all errors when check invalid Json against a valid schema from file" { $errorVar = $null - Test-Json -Json $invalidTypeInJson2 -SchemaPath $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue + Test-Json -Json $invalidTypeInJson2 -SchemaFile $validSchemaJsonPath -ErrorVariable errorVar -ErrorAction SilentlyContinue # '$invalidTypeInJson2' contains two errors in property types. $errorVar.Count | Should -Be 2 From 11a2d4f8013c330ffe296d74efabf16f8bbc1408 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Mon, 2 Mar 2020 22:56:45 +0300 Subject: [PATCH 12/28] Rename inner exception variable: "i" -> "ie" --- .../commands/utility/TestJsonCommand.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index ddd69bd6eb7..404e982047d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -74,17 +74,17 @@ protected override void BeginProcessing() catch (AggregateException ae) { // Process all exceptions in the AggregateException - ae.Handle(i => + ae.Handle(ie => { // Unwrap TargetInvocationException if any // Rethrow inner exception without losing the stack trace - if (i is TargetInvocationException) + if (ie is TargetInvocationException) { - ExceptionDispatchInfo.Capture(i.InnerException).Throw(); + ExceptionDispatchInfo.Capture(ie.InnerException).Throw(); } else { - ExceptionDispatchInfo.Capture(i).Throw(); + ExceptionDispatchInfo.Capture(ie).Throw(); } return true; } @@ -100,15 +100,15 @@ protected override void BeginProcessing() } catch (AggregateException ae) { - ae.Handle(i => + ae.Handle(ie => { - if (i is TargetInvocationException) + if (ie is TargetInvocationException) { - ExceptionDispatchInfo.Capture(i.InnerException).Throw(); + ExceptionDispatchInfo.Capture(ie.InnerException).Throw(); } else { - ExceptionDispatchInfo.Capture(i).Throw(); + ExceptionDispatchInfo.Capture(ie).Throw(); } return true; } From 0899edb7cff732858a644d77e16ac70596328a0b Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 3 Mar 2020 23:59:02 +0300 Subject: [PATCH 13/28] Convert delegates to private method --- .../commands/utility/TestJsonCommand.cs | 49 ++++++++----------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 404e982047d..0a6af5e3fa8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -54,6 +54,24 @@ 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. + /// + private static bool UnwrapException(Exception e) + { + if (e is TargetInvocationException) + { + ExceptionDispatchInfo.Capture(e.InnerException).Throw(); + } + else + { + ExceptionDispatchInfo.Capture(e).Throw(); + } + return true; + } + /// /// Prepare a JSON schema. /// @@ -73,22 +91,7 @@ protected override void BeginProcessing() // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library catch (AggregateException ae) { - // Process all exceptions in the AggregateException - ae.Handle(ie => - { - // Unwrap TargetInvocationException if any - // Rethrow inner exception without losing the stack trace - if (ie is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(ie.InnerException).Throw(); - } - else - { - ExceptionDispatchInfo.Capture(ie).Throw(); - } - return true; - } - ); + ae.Handle(UnwrapException); } } else if (SchemaFile != null) @@ -100,19 +103,7 @@ protected override void BeginProcessing() } catch (AggregateException ae) { - ae.Handle(ie => - { - if (ie is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(ie.InnerException).Throw(); - } - else - { - ExceptionDispatchInfo.Capture(ie).Throw(); - } - return true; - } - ); + ae.Handle(UnwrapException); } } } From 7b064f7a98ffc85b943f8c6ceb0cfc4b31c35da5 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Wed, 4 Mar 2020 00:02:14 +0300 Subject: [PATCH 14/28] Remove top-level declaration of the "resolvedpath" --- .../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 0a6af5e3fa8..563bffe919c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -77,8 +77,6 @@ private static bool UnwrapException(Exception e) /// protected override void BeginProcessing() { - string resolvedpath = string.Empty; - try { if (Schema != null) @@ -98,7 +96,7 @@ protected override void BeginProcessing() { try { - resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); + string resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; } catch (AggregateException ae) From 34f847332350e928b58c5d151c2ae64a7700a53d Mon Sep 17 00:00:00 2001 From: beatcracker Date: Wed, 4 Mar 2020 01:00:24 +0300 Subject: [PATCH 15/28] Sort usings --- .../commands/utility/TestJsonCommand.cs | 6 +++--- 1 file changed, 3 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 563bffe919c..31206f9f682 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -2,11 +2,11 @@ // Licensed under the MIT License. using System; -using System.Runtime.ExceptionServices; -using System.Reflection; -using System.Security; using System.IO; using System.Management.Automation; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Security; using Newtonsoft.Json.Linq; using NJsonSchema; From f002d31e7c0d580a768858998a776f41a68cd576 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 17 Mar 2020 22:04:41 +0300 Subject: [PATCH 16/28] Remove class name in parameter definition Co-Authored-By: Ilya --- .../commands/utility/TestJsonCommand.cs | 4 ++-- 1 file changed, 2 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 31206f9f682..56e0be6ef61 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -36,7 +36,7 @@ public class TestJsonCommand : PSCmdlet /// 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, ParameterSetName = TestJsonCommand.SchemaStringParameterSet)] + [Parameter(Position = 1, ParameterSetName = SchemaStringParameterSet)] [ValidateNotNullOrEmpty()] public string Schema { get; set; } @@ -48,7 +48,7 @@ public class TestJsonCommand : PSCmdlet /// 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, ParameterSetName = TestJsonCommand.SchemaFileParameterSet)] + [Parameter(Position = 1, ParameterSetName = SchemaFileParameterSet)] [ValidateNotNullOrEmpty()] public string SchemaFile { get; set; } From de7f360fafad9d854be7a7c6d3399e5456510601 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 17 Mar 2020 22:07:01 +0300 Subject: [PATCH 17/28] Simplify comment Co-Authored-By: Ilya --- .../commands/utility/TestJsonCommand.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 56e0be6ef61..256e24c64f6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -41,12 +41,8 @@ public class TestJsonCommand : PSCmdlet public string Schema { get; set; } /// - /// A path to the file containg schema to validate the JSON against. + /// A path to the file containg schema to validate the JSON string against. /// This is optional parameter. - /// If the parameter is absent the cmdlet only attempts to parse the JSON string. - /// If the parameter present the cmdlet attempts to parse the JSON string and - /// 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, ParameterSetName = SchemaFileParameterSet)] [ValidateNotNullOrEmpty()] From 046dc27206a4b2b25d79768eac559a777eec6114 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 17 Mar 2020 22:07:31 +0300 Subject: [PATCH 18/28] Simplify commment Co-Authored-By: Ilya --- .../commands/utility/TestJsonCommand.cs | 2 -- 1 file changed, 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 256e24c64f6..07a99b4196f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -110,8 +110,6 @@ e is NotSupportedException || e is SecurityException ) { - // Do we really need to wrap exception? Not doing this provides more clear error message upfront. - // E.g.: "'{}'|Test-Json -SchemaFile c:" results in "Test-Json : Access to the path 'C:\' is denied". Exception exception = new Exception("JSON schema file open failure", e); // TODO: Add resource string ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); } From 486bdaf3f9a446534fa85f5b0be5024797254f0e Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 17 Mar 2020 21:57:59 +0300 Subject: [PATCH 19/28] Remove comments --- .../Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 | 3 --- 1 file changed, 3 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 d14cbf4c785..6ca6511cd86 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -3,13 +3,10 @@ Describe "Test-Json" -Tags "CI" { BeforeAll { - # JSON schema referencing valid definitions $validSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath valid_schema_reference.json - # JSON schema referencing invalid definitions $invalidSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath invalid_schema_reference.json - # JSON schema file that doesn't exist $missingSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath no_such_file.json $validSchemaJson = @" From 3f179823b9bc1e4acd9a361d363eeb7ffea46c17 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Mon, 13 Apr 2020 22:37:33 +0300 Subject: [PATCH 20/28] Add resource string for "JsonSchemaFileOpenFailure" --- .../commands/utility/TestJsonCommand.cs | 2 +- .../resources/TestJsonCmdletStrings.resx | 3 +++ 2 files changed, 4 insertions(+), 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 07a99b4196f..e69e7dd37de 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -110,7 +110,7 @@ e is NotSupportedException || e is SecurityException ) { - Exception exception = new Exception("JSON schema file open failure", e); // TODO: Add resource string + Exception exception = new Exception(TestJsonCmdletStrings.JsonSchemaFileOpenFailure, e); ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); } catch (Exception e) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx index a5c8d5d24d9..e5b4aea283f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -126,4 +126,7 @@ The JSON is not valid with the schema. + + JSON schema file open failure + From 28e8c27c95991aceae735fae00fb57edc1365b23 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 14 Apr 2020 20:04:50 +0300 Subject: [PATCH 21/28] Change resource string wording to include filename Co-Authored-By: Ilya --- .../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 e5b4aea283f..ab105e47fd3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -127,6 +127,6 @@ The JSON is not valid with the schema. - JSON schema file open failure + Can not open JSON schema file: {0} From 8116c238babee4edc57e17ecb353390eed726b66 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Tue, 14 Apr 2020 21:35:15 +0300 Subject: [PATCH 22/28] Add file path to the "JsonSchemaFileOpenFailure" error message --- .../commands/utility/TestJsonCommand.cs | 10 ++++++++-- 1 file changed, 8 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 e69e7dd37de..f824ff33c7d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Globalization; using System.IO; using System.Management.Automation; using System.Reflection; @@ -73,6 +74,8 @@ private static bool UnwrapException(Exception e) /// protected override void BeginProcessing() { + string resolvedpath = string.Empty; + try { if (Schema != null) @@ -92,7 +95,7 @@ protected override void BeginProcessing() { try { - string resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); + resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; } catch (AggregateException ae) @@ -110,7 +113,10 @@ e is NotSupportedException || e is SecurityException ) { - Exception exception = new Exception(TestJsonCmdletStrings.JsonSchemaFileOpenFailure, e); + Exception exception = new Exception(string.Format( + CultureInfo.CurrentUICulture, + TestJsonCmdletStrings.JsonSchemaFileOpenFailure, + resolvedpath), e); ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); } catch (Exception e) From 80a2671cf1a8e0c453a34e9730406706fb4bcf39 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Thu, 16 Apr 2020 17:51:19 +0300 Subject: [PATCH 23/28] Add schema path as a targetObject to the ErrorRecord --- .../commands/utility/TestJsonCommand.cs | 4 ++-- 1 file changed, 2 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 f824ff33c7d..69182e854df 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -117,12 +117,12 @@ e is SecurityException CultureInfo.CurrentUICulture, TestJsonCmdletStrings.JsonSchemaFileOpenFailure, resolvedpath), e); - ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, null)); + ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, resolvedpath)); } catch (Exception e) { Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, e); - ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, null)); + ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, resolvedpath)); } } From 60825220bf105d0ccf54ee8969153e1647d5248a Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 19 Apr 2020 00:27:09 +0300 Subject: [PATCH 24/28] Fix Codefactor warnings --- .../commands/utility/TestJsonCommand.cs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 69182e854df..afd8786f2e0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -8,7 +8,6 @@ using System.Reflection; using System.Runtime.ExceptionServices; using System.Security; - using Newtonsoft.Json.Linq; using NJsonSchema; @@ -38,7 +37,7 @@ public class TestJsonCommand : PSCmdlet /// the cmdlet parses the schema doing implicitly check the schema too. /// [Parameter(Position = 1, ParameterSetName = SchemaStringParameterSet)] - [ValidateNotNullOrEmpty()] + [ValidateNotNullOrEmpty] public string Schema { get; set; } /// @@ -46,7 +45,7 @@ public class TestJsonCommand : PSCmdlet /// This is optional parameter. /// [Parameter(Position = 1, ParameterSetName = SchemaFileParameterSet)] - [ValidateNotNullOrEmpty()] + [ValidateNotNullOrEmpty] public string SchemaFile { get; set; } private JsonSchema _jschema; @@ -56,6 +55,8 @@ public class TestJsonCommand : PSCmdlet /// 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 is TargetInvocationException) @@ -84,10 +85,11 @@ protected override void BeginProcessing() { _jschema = JsonSchema.FromJsonAsync(Schema).Result; } - // 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 catch (AggregateException ae) { + // 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); } } @@ -104,19 +106,23 @@ protected override void BeginProcessing() } } } - // Handle exceptions related to file access to provide more specific error message - // https://docs.microsoft.com/en-us/dotnet/standard/io/handling-io-errors catch (Exception e) when ( + // Handle exceptions related to file access to provide more specific error message + // https://docs.microsoft.com/en-us/dotnet/standard/io/handling-io-errors + e is IOException || e is UnauthorizedAccessException || e is NotSupportedException || e is SecurityException ) { - Exception exception = new Exception(string.Format( - CultureInfo.CurrentUICulture, - TestJsonCmdletStrings.JsonSchemaFileOpenFailure, - resolvedpath), e); + Exception exception = new Exception( + string.Format( + CultureInfo.CurrentUICulture, + TestJsonCmdletStrings.JsonSchemaFileOpenFailure, + resolvedpath), + e + ); ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, resolvedpath)); } catch (Exception e) From 735683c47b3e0f6ad1b2a8fb000b9ae802e6b47d Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 19 Apr 2020 00:31:56 +0300 Subject: [PATCH 25/28] Fix Codefactor warnings --- .../commands/utility/TestJsonCommand.cs | 5 +---- 1 file changed, 1 insertion(+), 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 afd8786f2e0..d5f96b27c4e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -89,7 +89,6 @@ protected override void BeginProcessing() { // 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); } } @@ -109,7 +108,6 @@ protected override void BeginProcessing() catch (Exception e) when ( // Handle exceptions related to file access to provide more specific error message // https://docs.microsoft.com/en-us/dotnet/standard/io/handling-io-errors - e is IOException || e is UnauthorizedAccessException || e is NotSupportedException || @@ -121,8 +119,7 @@ e is SecurityException CultureInfo.CurrentUICulture, TestJsonCmdletStrings.JsonSchemaFileOpenFailure, resolvedpath), - e - ); + e); ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, resolvedpath)); } catch (Exception e) From a724c7c28585ba2766b0ae043a5842ea78d03d55 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sun, 19 Apr 2020 00:42:55 +0300 Subject: [PATCH 26/28] Fix Codefactor warnings --- .../commands/utility/TestJsonCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index d5f96b27c4e..46a1a4cbc08 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -67,6 +67,7 @@ private static bool UnwrapException(Exception e) { ExceptionDispatchInfo.Capture(e).Throw(); } + return true; } From 80e0006c7f740c3526d372797af629a61d472150 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Sat, 2 May 2020 01:05:03 +0300 Subject: [PATCH 27/28] Fix SA1623 for CodeFactor --- .../commands/utility/TestJsonCommand.cs | 6 +++--- 1 file changed, 3 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 46a1a4cbc08..1ff5f64271d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -23,13 +23,13 @@ public class TestJsonCommand : PSCmdlet private const string SchemaStringParameterSet = "SchemaString"; /// - /// A JSON string to be validated. + /// Gets or sets JSON string to be validated. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] public string Json { get; set; } /// - /// A schema to validate the JSON against. + /// Gets or sets schema to validate the JSON against. /// This is optional parameter. /// If the parameter is absent the cmdlet only attempts to parse the JSON string. /// If the parameter present the cmdlet attempts to parse the JSON string and @@ -41,7 +41,7 @@ public class TestJsonCommand : PSCmdlet public string Schema { get; set; } /// - /// A path to the file containg schema to validate the JSON string against. + /// Gets or sets path to the file containg schema to validate the JSON string against. /// This is optional parameter. /// [Parameter(Position = 1, ParameterSetName = SchemaFileParameterSet)] From 8429e2ff9db80866788310b91879e76c825111e1 Mon Sep 17 00:00:00 2001 From: beatcracker Date: Thu, 28 May 2020 23:12:43 +0300 Subject: [PATCH 28/28] Add HelpUri Co-authored-by: Aditya Patwardhan --- .../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 1ff5f64271d..42926643e45 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -16,7 +16,7 @@ namespace Microsoft.PowerShell.Commands /// /// This class implements Test-Json command. /// - [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "")] + [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096609")] public class TestJsonCommand : PSCmdlet { private const string SchemaFileParameterSet = "SchemaFile";