@@ -115,7 +115,9 @@ function Split-YamlSuiteJsonDocument {
115115function ConvertTo-YamlSuiteCanonicalValue {
116116 param (
117117 [AllowNull ()]
118- [object ] $Value
118+ [object ] $Value ,
119+
120+ [switch ] $SortMappings
119121 )
120122
121123 if ($null -eq $Value -or $Value -is [System.DBNull ]) {
@@ -127,6 +129,32 @@ function ConvertTo-YamlSuiteCanonicalValue {
127129 if ($Value -is [bool ]) {
128130 return ' bool:{0}' -f $Value.ToString ().ToLowerInvariant()
129131 }
132+ if ($Value -is [byte []]) {
133+ return ' binary:{0}:{1}' -f $Value.Length , [System.Convert ]::ToBase64String($Value )
134+ }
135+ if ($Value -is [char ]) {
136+ return ' char:{0}' -f [int ] $Value
137+ }
138+ if ($Value.GetType ().IsEnum) {
139+ return ' enum:{0}:{1}' -f $Value.GetType ().FullName, (
140+ [System.Convert ]::ToUInt64($Value , [cultureinfo ]::InvariantCulture)
141+ )
142+ }
143+ if ($Value -is [datetimeoffset ]) {
144+ return ' timestamp:{0}:{1}' -f $Value.UtcTicks , $Value.Offset.Ticks
145+ }
146+ if ($Value -is [datetime ]) {
147+ return ' datetime:{0}:{1}' -f $Value.Ticks , [int ] $Value.Kind
148+ }
149+ if ($Value -is [timespan ]) {
150+ return ' timespan:{0}' -f $Value.Ticks
151+ }
152+ if ($Value -is [guid ]) {
153+ return ' guid:{0}' -f $Value.ToString (' D' )
154+ }
155+ if ($Value -is [uri ]) {
156+ return ' uri:{0}:{1}' -f $Value.OriginalString.Length , $Value.OriginalString
157+ }
130158
131159 $typeCode = [System.Type ]::GetTypeCode($Value.GetType ())
132160 if ($Value -is [System.Numerics.BigInteger ] -or $typeCode -in @ (
@@ -149,27 +177,48 @@ function ConvertTo-YamlSuiteCanonicalValue {
149177 }
150178 if ($Value -is [System.Collections.IDictionary ]) {
151179 $entries = [System.Collections.Generic.List [string ]]::new()
152- foreach ($key in $Value.Keys ) {
153- if ($key -isnot [string ]) {
154- return ' unsupported:non-string-mapping-key'
155- }
156- $canonicalValue = ConvertTo-YamlSuiteCanonicalValue - Value $Value [$key ]
157- $entries.Add ((' {0}:{1}={2}' -f $key.Length , $key , $canonicalValue ))
180+ foreach ($entry in $Value.GetEnumerator ()) {
181+ $canonicalKey = ConvertTo-YamlSuiteCanonicalValue - Value $entry.Key `
182+ - SortMappings:$SortMappings
183+ $canonicalValue = ConvertTo-YamlSuiteCanonicalValue - Value $entry.Value `
184+ - SortMappings:$SortMappings
185+ $entries.Add ((' {0}:{1}={2}:{3}' -f
186+ $canonicalKey.Length ,
187+ $canonicalKey ,
188+ $canonicalValue.Length ,
189+ $canonicalValue
190+ ))
191+ }
192+ $isOrdered = (
193+ $Value -is [System.Collections.Specialized.OrderedDictionary ] -or
194+ $Value.GetType ().FullName -ceq ' System.Management.Automation.OrderedHashtable'
195+ )
196+ if ($SortMappings -or -not $isOrdered ) {
197+ $entries.Sort ([System.StringComparer ]::Ordinal)
158198 }
159- $entries.Sort ([System.StringComparer ]::Ordinal)
160199 return ' map:{0}:{{{1}}}' -f $entries.Count , ($entries -join ' |' )
161200 }
162201 if ($Value -is [System.Collections.IEnumerable ] -and $Value -isnot [string ]) {
163- if ($Value -is [byte []]) {
164- return ' unsupported:System.Byte[]'
165- }
166202 $items = [System.Collections.Generic.List [string ]]::new()
167203 foreach ($item in $Value ) {
168- $items.Add ((ConvertTo-YamlSuiteCanonicalValue - Value $item ))
204+ $items.Add ((
205+ ConvertTo-YamlSuiteCanonicalValue - Value $item - SortMappings:$SortMappings
206+ ))
169207 }
170208 return ' sequence:{0}:[{1}]' -f $items.Count , ($items -join ' |' )
171209 }
172- return ' unsupported:{0}' -f $Value.GetType ().FullName
210+
211+ $serialized = [System.Management.Automation.PSSerializer ]::Serialize($Value , 3 )
212+ $payload = [System.Convert ]::ToBase64String(
213+ [System.Text.Encoding ]::UTF8.GetBytes($serialized )
214+ )
215+ if (-not $Value.GetType ().IsValueType) {
216+ return ' unsupported-reference:{0}:{1}:{2}' -f
217+ $Value.GetType ().FullName,
218+ [System.Runtime.CompilerServices.RuntimeHelpers ]::GetHashCode($Value ),
219+ $payload
220+ }
221+ return ' unsupported-value:{0}:{1}' -f $Value.GetType ().FullName, $payload
173222}
174223
175224function ConvertTo-YamlSuiteReferenceSignature {
@@ -188,7 +237,7 @@ function ConvertTo-YamlSuiteReferenceSignature {
188237 while ($stack.Count -gt 0 ) {
189238 $frame = $stack.Pop ()
190239 $current = $frame.Value
191- if ($null -eq $current -or $current -is [string ] -or $current -is [ byte []] ) {
240+ if ($null -eq $current -or $current -is [string ]) {
192241 continue
193242 }
194243 if ($current -isnot [System.Collections.IDictionary ] -and
@@ -206,13 +255,22 @@ function ConvertTo-YamlSuiteReferenceSignature {
206255 if (-not $first ) {
207256 continue
208257 }
258+ if ($current -is [byte []]) {
259+ continue
260+ }
209261
210262 if ($current -is [System.Collections.IDictionary ]) {
211- foreach ($key in $current.Keys ) {
212- $childPath = ' {0}{{{1}}}' -f $frame.Path , (ConvertTo-YamlSuiteCanonicalValue - Value $key )
263+ foreach ($entry in $current.GetEnumerator ()) {
264+ $childPath = ' {0}{{{1}}}' -f $frame.Path , (
265+ ConvertTo-YamlSuiteCanonicalValue - Value $entry.Key
266+ )
213267 $stack.Push ([pscustomobject ]@ {
214- Value = $current [$key ]
215- Path = $childPath
268+ Value = $entry.Value
269+ Path = " $childPath .value"
270+ })
271+ $stack.Push ([pscustomobject ]@ {
272+ Value = $entry.Key
273+ Path = " $childPath .key"
216274 })
217275 }
218276 continue
@@ -333,32 +391,23 @@ function Test-YamlSuiteLegacyOrderedMapProjection {
333391function Get-YamlSuiteJsonPolicyReason {
334392 [OutputType ([string ])]
335393 param (
336- [Parameter (Mandatory )]
337- [string ] $Case ,
338-
339394 [Parameter (Mandatory )]
340395 [object []] $ExpectedValues ,
341396
342397 [Parameter (Mandatory )]
343398 [object []] $ActualValues
344399 )
345400
346- switch - CaseSensitive ($Case ) {
347- ' 565N' {
348- if (Test-YamlSuiteBinaryByteArrayProjection - ExpectedValues $ExpectedValues `
349- - ActualValues $ActualValues ) {
350- return ' BinaryByteArrayProjection'
351- }
352- }
353- ' J7PZ' {
354- if (Test-YamlSuiteLegacyOrderedMapProjection - ExpectedValues $ExpectedValues `
355- - ActualValues $ActualValues ) {
356- return ' LegacyOrderedMapProjection'
357- }
358- }
359- default { return ' ' }
401+ if (Test-YamlSuiteBinaryByteArrayProjection - ExpectedValues $ExpectedValues `
402+ - ActualValues $ActualValues ) {
403+ return ' BinaryByteArrayProjection'
404+ }
405+ if (Test-YamlSuiteLegacyOrderedMapProjection - ExpectedValues $ExpectedValues `
406+ - ActualValues $ActualValues ) {
407+ return ' LegacyOrderedMapProjection'
360408 }
361409 return ' '
410+ return ' '
362411}
363412
364413function ConvertFrom-YamlSuiteEventText {
@@ -749,13 +798,15 @@ foreach ($inputFile in $inputFiles) {
749798 $stream = $null
750799 $projectedValues = $null
751800 $projectedCanonical = $null
801+ $projectedJsonCanonical = $null
752802 $projectedReference = ' '
753803 $projectionError = ' '
754804 $eventExpected = $null
755805 $eventActual = $null
756806 $jsonExpected = $null
757807 $jsonActual = $null
758808 $outYamlCanonical = $null
809+ $outYamlReference = $null
759810 $emitCanonical = $null
760811 $emitReference = $null
761812
@@ -801,6 +852,8 @@ foreach ($inputFile in $inputFiles) {
801852 try {
802853 $projectedValues = (Invoke-InYamlModule - ScriptBlock $projectYamlSuiteStream - Arguments (, $stream.Value )).Value
803854 $projectedCanonical = ConvertTo-YamlSuiteCanonicalValue - Value ([object []] $projectedValues )
855+ $projectedJsonCanonical = ConvertTo-YamlSuiteCanonicalValue `
856+ - Value ([object []] $projectedValues ) - SortMappings
804857 $projectedReference = ConvertTo-YamlSuiteReferenceSignature - Value ([object []] $projectedValues )
805858 } catch {
806859 if ($_.Exception.Data.Contains (' YamlErrorId' )) {
@@ -845,13 +898,14 @@ foreach ($inputFile in $inputFiles) {
845898 foreach ($document in $expectedDocuments ) {
846899 $expectedValues.Add ((ConvertFrom-Json - InputObject $document - AsHashtable - NoEnumerate))
847900 }
848- $expectedCanonical = ConvertTo-YamlSuiteCanonicalValue - Value ([object []] $expectedValues.ToArray ())
901+ $expectedCanonical = ConvertTo-YamlSuiteCanonicalValue `
902+ - Value ([object []] $expectedValues.ToArray ()) - SortMappings
849903 $jsonExpected = $expectedCanonical
850- $jsonActual = $projectedCanonical
851- if ($projectedCanonical -ceq $expectedCanonical ) {
904+ $jsonActual = $projectedJsonCanonical
905+ if ($projectedJsonCanonical -ceq $expectedCanonical ) {
852906 $jsonResult = ' Pass'
853907 } else {
854- $reason = Get-YamlSuiteJsonPolicyReason - Case $casePath `
908+ $reason = Get-YamlSuiteJsonPolicyReason `
855909 - ExpectedValues ([object []] $expectedValues.ToArray ()) `
856910 - ActualValues ([object []] $projectedValues )
857911 if ($reason ) {
@@ -877,12 +931,17 @@ foreach ($inputFile in $inputFiles) {
877931 $outStream = Invoke-InYamlModule - ScriptBlock $readYamlSuiteStream - Arguments @ ($outYaml )
878932 $outValues = (Invoke-InYamlModule - ScriptBlock $projectYamlSuiteStream - Arguments (, $outStream.Value )).Value
879933 $outCanonical = ConvertTo-YamlSuiteCanonicalValue - Value ([object []] $outValues )
934+ $outReference = ConvertTo-YamlSuiteReferenceSignature - Value ([object []] $outValues )
880935 $outYamlCanonical = $outCanonical
881- if ($outCanonical -ceq $projectedCanonical ) {
882- $outYamlResult = ' Pass'
883- } else {
936+ $outYamlReference = $outReference
937+ if ($outCanonical -cne $projectedCanonical ) {
884938 $outYamlResult = ' Fail'
885939 $outYamlReason = ' OutYamlConstructionMismatch'
940+ } elseif ($outReference -cne $projectedReference ) {
941+ $outYamlResult = ' Fail'
942+ $outYamlReason = ' OutYamlReferenceMismatch'
943+ } else {
944+ $outYamlResult = ' Pass'
886945 }
887946 } catch {
888947 if ($_.Exception.Data.Contains (' IsYamlException' )) {
@@ -975,6 +1034,7 @@ foreach ($inputFile in $inputFiles) {
9751034 JsonExpected = $jsonExpected
9761035 JsonActual = $jsonActual
9771036 OutYamlActual = $outYamlCanonical
1037+ OutYamlRefs = $outYamlReference
9781038 EmitActual = $emitCanonical
9791039 EmitReferences = $emitReference
9801040 ProjectedActual = $projectedCanonical
0 commit comments