diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs
index 9d792b9123..fc416d9772 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs
@@ -16,19 +16,63 @@ namespace Microsoft.PowerShell.Commands
///
/// This class implements Test-Json command.
///
- [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = ParameterAttribute.AllParameterSets, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096609")]
+ [Cmdlet(VerbsDiagnostic.Test, "Json", DefaultParameterSetName = JsonStringParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096609")]
[OutputType(typeof(bool))]
public class TestJsonCommand : PSCmdlet
{
- private const string SchemaFileParameterSet = "SchemaFile";
- private const string SchemaStringParameterSet = "SchemaString";
+ #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
///
/// Gets or sets JSON string to be validated.
///
- [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)]
+ [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)]
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.
@@ -37,7 +81,9 @@ namespace Microsoft.PowerShell.Commands
/// 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 = SchemaStringParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonStringWithSchemaStringParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonPathWithSchemaStringParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonLiteralPathWithSchemaStringParameterSet)]
[ValidateNotNullOrEmpty]
public string Schema { get; set; }
@@ -45,10 +91,17 @@ namespace Microsoft.PowerShell.Commands
/// Gets or sets path to the file containing schema to validate the JSON string against.
/// This is optional parameter.
///
- [Parameter(Position = 1, ParameterSetName = SchemaFileParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonStringWithSchemaFileParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonPathWithSchemaFileParameterSet)]
+ [Parameter(Position = 1, Mandatory = true, ParameterSetName = JsonLiteralPathWithSchemaFileParameterSet)]
[ValidateNotNullOrEmpty]
public string SchemaFile { get; set; }
+ #endregion
+
+ #region Private Members
+
+ private bool _isLiteralPath = false;
private JsonSchema _jschema;
///
@@ -72,6 +125,10 @@ namespace Microsoft.PowerShell.Commands
return true;
}
+ #endregion
+
+ #region Protected Members
+
///
/// Prepare a JSON schema.
///
@@ -137,10 +194,38 @@ namespace Microsoft.PowerShell.Commands
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(Json);
+ var parsedJson = JToken.Parse(jsonToParse);
if (_jschema != null)
{
@@ -165,10 +250,12 @@ namespace Microsoft.PowerShell.Commands
result = false;
Exception exception = new(TestJsonCmdletStrings.InvalidJson, exc);
- WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, Json));
+ WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, jsonToParse));
}
WriteObject(result);
}
+
+ #endregion
}
}
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 2ea76f5826..9e949e0215 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1
@@ -3,11 +3,11 @@
Describe "Test-Json" -Tags "CI" {
BeforeAll {
- $validSchemaJsonPath = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath valid_schema_reference.json
-
- $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
+ $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
$validSchemaJson = @"
{
@@ -65,48 +65,139 @@ Describe "Test-Json" -Tags "CI" {
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 @(
@@ -133,6 +224,30 @@ 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
@@ -153,6 +268,26 @@ 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' }