From d0f81ea7b89c401e3a2bea3d71efd9acfec09c7c Mon Sep 17 00:00:00 2001 From: Bernie White Date: Fri, 22 Mar 2019 08:57:39 +1000 Subject: [PATCH] Fix deserialization of nested JSON arrays #109 (#110) - Fix incorrect JSON de-serialization of nested arrays. #109 --- CHANGELOG.md | 2 ++ src/PSRule/Common/JsonConverters.cs | 31 +++++++++++++++++++ src/PSRule/Common/YamlConverters.cs | 6 ++-- tests/PSRule.Tests/FromFile.Rule.ps1 | 1 + .../InputFormatDeserializerTests.cs | 2 ++ tests/PSRule.Tests/ObjectFromFile.json | 20 ++++++++++-- tests/PSRule.Tests/ObjectFromFile.yaml | 7 +++++ tests/PSRule.Tests/ObjectFromFile2.yaml | 3 ++ tests/PSRule.Tests/PSRule.Common.Tests.ps1 | 2 ++ 9 files changed, 69 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 571d5a23ce..6fb2668c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Unreleased +- Fix incorrect JSON de-serialization of nested arrays. [#109](https://github.com/BernieWhite/PSRule/issues/109) + ## v0.4.0-B190311 (pre-release) - Added support for using `-InputPath` instead of using `-InputObject` to handle serialized objects. [#106](https://github.com/BernieWhite/PSRule/issues/106) diff --git a/src/PSRule/Common/JsonConverters.cs b/src/PSRule/Common/JsonConverters.cs index 54868e7ff1..580d934ac1 100644 --- a/src/PSRule/Common/JsonConverters.cs +++ b/src/PSRule/Common/JsonConverters.cs @@ -76,6 +76,22 @@ private void ReadObject(PSObject value, JsonReader reader) value.Properties.Add(new PSNoteProperty(name: name, value: child)); break; + case JsonToken.StartArray: + var items = new List(); + reader.Read(); + var item = new PSObject(); + + while (reader.TokenType != JsonToken.EndArray) + { + ReadObject(value: item, reader: reader); + items.Add(item); + reader.Read(); + } + + value.Properties.Add(new PSNoteProperty(name: name, value: items.ToArray())); + + break; + default: value.Properties.Add(new PSNoteProperty(name: name, value: reader.Value)); break; @@ -161,6 +177,21 @@ private PSObject ReadObject(JsonReader reader) result.Properties.Add(new PSNoteProperty(name: name, value: value)); break; + case JsonToken.StartArray: + var items = new List(); + reader.Read(); + + while (reader.TokenType != JsonToken.EndArray) + { + var item = ReadObject(reader: reader); + items.Add(item); + reader.Read(); + } + + result.Properties.Add(new PSNoteProperty(name: name, value: items.ToArray())); + + break; + default: result.Properties.Add(new PSNoteProperty(name: name, value: reader.Value)); break; diff --git a/src/PSRule/Common/YamlConverters.cs b/src/PSRule/Common/YamlConverters.cs index 315d9300cc..b4137d6041 100644 --- a/src/PSRule/Common/YamlConverters.cs +++ b/src/PSRule/Common/YamlConverters.cs @@ -111,17 +111,17 @@ public object ReadYaml(IParser parser, Type type) { parser.MoveNext(); - var values = new List(); + var values = new List(); while (!parser.Accept()) { if (parser.Accept()) { - values.Add(ReadYaml(parser, type)); + values.Add(PSObject.AsPSObject(ReadYaml(parser, type))); } else if (parser.Accept()) { - values.Add(parser.Allow().Value); + values.Add(PSObject.AsPSObject(parser.Allow().Value)); } } diff --git a/tests/PSRule.Tests/FromFile.Rule.ps1 b/tests/PSRule.Tests/FromFile.Rule.ps1 index 274eac758f..b8a9b69e17 100644 --- a/tests/PSRule.Tests/FromFile.Rule.ps1 +++ b/tests/PSRule.Tests/FromFile.Rule.ps1 @@ -132,6 +132,7 @@ Rule 'WithConfiguration' { Rule 'WithFormat' { $TargetObject.spec.properties.kind -eq 'Test' + ($TargetObject.spec.properties.array.id | Measure-Object).Count -eq 2 } # Description: Test for Hint keyword diff --git a/tests/PSRule.Tests/InputFormatDeserializerTests.cs b/tests/PSRule.Tests/InputFormatDeserializerTests.cs index d309581212..371eb7ac7c 100644 --- a/tests/PSRule.Tests/InputFormatDeserializerTests.cs +++ b/tests/PSRule.Tests/InputFormatDeserializerTests.cs @@ -18,6 +18,7 @@ public void DeserializeObjectsYaml() Assert.Equal("TestObject1", actual[0].Properties["targetName"].Value); Assert.Equal("Test", actual[0].PropertyValue("spec").PropertyValue("properties").PropertyValue("kind")); Assert.Equal(2, actual[1].PropertyValue("spec").PropertyValue("properties").PropertyValue("value2")); + Assert.Equal(2, actual[1].PropertyValue("spec").PropertyValue("properties").PropertyValue("array").Length); } [Fact] @@ -29,6 +30,7 @@ public void DeserialObjectsJson() Assert.Equal("TestObject1", actual[0].Properties["targetName"].Value); Assert.Equal("Test", actual[0].PropertyValue("spec").PropertyValue("properties").PropertyValue("kind")); Assert.Equal(2, actual[1].PropertyValue("spec").PropertyValue("properties").PropertyValue("value2")); + Assert.Equal(2, actual[1].PropertyValue("spec").PropertyValue("properties").PropertyValue("array").Length); } private string GetYamlContent() diff --git a/tests/PSRule.Tests/ObjectFromFile.json b/tests/PSRule.Tests/ObjectFromFile.json index fd9a69ebbc..532087b137 100644 --- a/tests/PSRule.Tests/ObjectFromFile.json +++ b/tests/PSRule.Tests/ObjectFromFile.json @@ -4,7 +4,15 @@ "Spec": { "Properties": { "Value1": 1, - "Kind": "Test" + "Kind": "Test", + "array": [ + { + "id": "1" + }, + { + "id": "2" + } + ] } } }, @@ -13,7 +21,15 @@ "Spec": { "Properties": { "Value2": 2, - "Kind": "Test" + "Kind": "Test", + "array": [ + { + "id": "1" + }, + { + "id": "2" + } + ] } } } diff --git a/tests/PSRule.Tests/ObjectFromFile.yaml b/tests/PSRule.Tests/ObjectFromFile.yaml index c52bc3ead7..e703927c0f 100644 --- a/tests/PSRule.Tests/ObjectFromFile.yaml +++ b/tests/PSRule.Tests/ObjectFromFile.yaml @@ -6,12 +6,19 @@ spec: properties: value1: 1 kind: Test + array: + - id: 1 + - id: 2 + --- targetName: TestObject2 spec: properties: value2: 2 kind: Test + array: + - id: 1 + - id: 2 --- # Null object diff --git a/tests/PSRule.Tests/ObjectFromFile2.yaml b/tests/PSRule.Tests/ObjectFromFile2.yaml index cd9a08ff74..ef0a0805d5 100644 --- a/tests/PSRule.Tests/ObjectFromFile2.yaml +++ b/tests/PSRule.Tests/ObjectFromFile2.yaml @@ -6,3 +6,6 @@ spec: properties: value1: 3 kind: Test + array: + - id: 1 + - id: 2 diff --git a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 index ca22d508c9..b0102635a3 100644 --- a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 @@ -304,6 +304,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { It 'Yaml' { $result = @(Invoke-PSRule -Path (Join-Path -Path $here -ChildPath 'FromFile.Rule.ps1') -Name 'WithFormat' -InputPath (Join-Path -Path $here -ChildPath 'ObjectFromFile*.yaml')); $result | Should -Not -BeNullOrEmpty; + $result.IsSuccess() | Should -BeIn $True; $result.Length | Should -Be 3; $result | Should -BeOfType PSRule.Rules.RuleRecord; $result.TargetName | Should -BeIn 'TestObject1', 'TestObject2', 'TestObject3'; @@ -312,6 +313,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { It 'Json' { $result = @(Invoke-PSRule -Path (Join-Path -Path $here -ChildPath 'FromFile.Rule.ps1') -Name 'WithFormat' -InputPath (Join-Path -Path $here -ChildPath 'ObjectFromFile.json')); $result | Should -Not -BeNullOrEmpty; + $result.IsSuccess() | Should -BeIn $True; $result.Length | Should -Be 2; $result | Should -BeOfType PSRule.Rules.RuleRecord; $result.TargetName | Should -BeIn 'TestObject1', 'TestObject2';