Skip to content

Commit

Permalink
Fix deserialization of nested JSON arrays #109 (#110)
Browse files Browse the repository at this point in the history
- Fix incorrect JSON de-serialization of nested arrays. #109
  • Loading branch information
BernieWhite authored Mar 21, 2019
1 parent 9c5522b commit d0f81ea
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
31 changes: 31 additions & 0 deletions src/PSRule/Common/JsonConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PSObject>();
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;
Expand Down Expand Up @@ -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<PSObject>();
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;
Expand Down
6 changes: 3 additions & 3 deletions src/PSRule/Common/YamlConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,17 @@ public object ReadYaml(IParser parser, Type type)
{
parser.MoveNext();

var values = new List<object>();
var values = new List<PSObject>();

while (!parser.Accept<SequenceEnd>())
{
if (parser.Accept<MappingStart>())
{
values.Add(ReadYaml(parser, type));
values.Add(PSObject.AsPSObject(ReadYaml(parser, type)));
}
else if (parser.Accept<Scalar>())
{
values.Add(parser.Allow<Scalar>().Value);
values.Add(PSObject.AsPSObject(parser.Allow<Scalar>().Value));
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/PSRule.Tests/FromFile.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/PSRule.Tests/InputFormatDeserializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public void DeserializeObjectsYaml()
Assert.Equal("TestObject1", actual[0].Properties["targetName"].Value);
Assert.Equal("Test", actual[0].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<string>("kind"));
Assert.Equal(2, actual[1].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<int>("value2"));
Assert.Equal(2, actual[1].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<PSObject[]>("array").Length);
}

[Fact]
Expand All @@ -29,6 +30,7 @@ public void DeserialObjectsJson()
Assert.Equal("TestObject1", actual[0].Properties["targetName"].Value);
Assert.Equal("Test", actual[0].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<string>("kind"));
Assert.Equal(2, actual[1].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<int>("value2"));
Assert.Equal(2, actual[1].PropertyValue<PSObject>("spec").PropertyValue<PSObject>("properties").PropertyValue<PSObject[]>("array").Length);
}

private string GetYamlContent()
Expand Down
20 changes: 18 additions & 2 deletions tests/PSRule.Tests/ObjectFromFile.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
"Spec": {
"Properties": {
"Value1": 1,
"Kind": "Test"
"Kind": "Test",
"array": [
{
"id": "1"
},
{
"id": "2"
}
]
}
}
},
Expand All @@ -13,7 +21,15 @@
"Spec": {
"Properties": {
"Value2": 2,
"Kind": "Test"
"Kind": "Test",
"array": [
{
"id": "1"
},
{
"id": "2"
}
]
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions tests/PSRule.Tests/ObjectFromFile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions tests/PSRule.Tests/ObjectFromFile2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ spec:
properties:
value1: 3
kind: Test
array:
- id: 1
- id: 2
2 changes: 2 additions & 0 deletions tests/PSRule.Tests/PSRule.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand Down

0 comments on commit d0f81ea

Please sign in to comment.