1
0
mirror of https://github.com/PowerShell/PowerShell synced 2025-10-06 00:22:59 +02:00

Treat large Enum values as numbers in ConvertTo-Json (#20999)

This commit is contained in:
Jordan Borean
2024-09-20 03:24:20 +10:00
committed by GitHub
parent 805e621517
commit 3e3d83cfa4
7 changed files with 64 additions and 20 deletions

View File

@@ -2,6 +2,7 @@
"PSFeedbackProvider", "PSFeedbackProvider",
"PSLoadAssemblyFromNativeCode", "PSLoadAssemblyFromNativeCode",
"PSNativeWindowsTildeExpansion", "PSNativeWindowsTildeExpansion",
"PSSerializeJSONLongEnumAsNumber",
"PSRedirectToVariable", "PSRedirectToVariable",
"PSSubsystemPluginModel" "PSSubsystemPluginModel"
] ]

View File

@@ -2,6 +2,7 @@
"PSFeedbackProvider", "PSFeedbackProvider",
"PSLoadAssemblyFromNativeCode", "PSLoadAssemblyFromNativeCode",
"PSNativeWindowsTildeExpansion", "PSNativeWindowsTildeExpansion",
"PSSerializeJSONLongEnumAsNumber",
"PSRedirectToVariable", "PSRedirectToVariable",
"PSSubsystemPluginModel" "PSSubsystemPluginModel"
] ]

View File

@@ -577,7 +577,7 @@ namespace Microsoft.PowerShell.Commands
{ {
Type t = obj.GetType(); Type t = obj.GetType();
if (t.IsPrimitive) if (t.IsPrimitive || (t.IsEnum && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSSerializeJSONLongEnumAsNumber)))
{ {
rv = obj; rv = obj;
} }

View File

@@ -24,6 +24,7 @@ namespace System.Management.Automation
internal const string PSFeedbackProvider = "PSFeedbackProvider"; internal const string PSFeedbackProvider = "PSFeedbackProvider";
internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion);
internal const string PSRedirectToVariable = "PSRedirectToVariable"; internal const string PSRedirectToVariable = "PSRedirectToVariable";
internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber);
#endregion #endregion
@@ -121,6 +122,10 @@ namespace System.Management.Automation
new ExperimentalFeature( new ExperimentalFeature(
name: PSRedirectToVariable, name: PSRedirectToVariable,
description: "Add support for redirecting to the variable drive"), description: "Add support for redirecting to the variable drive"),
new ExperimentalFeature(
name: PSSerializeJSONLongEnumAsNumber,
description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json."
)
}; };
EngineExperimentalFeatures = new ReadOnlyCollection<ExperimentalFeature>(engineFeatures); EngineExperimentalFeatures = new ReadOnlyCollection<ExperimentalFeature>(engineFeatures);

View File

@@ -0,0 +1,34 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Describe 'ConvertTo-Json with PSSerializeJSONLongEnumAsNumber' -tags "CI" {
BeforeAll {
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues['It:Skip'] = -not [ExperimentalFeature]::IsEnabled('PSSerializeJSONLongEnumAsNumber')
}
AfterAll {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
It 'Should treat enums as integers' {
enum LongEnum : long {
LongValue = -1
}
enum ULongEnum : ulong {
ULongValue = 18446744073709551615
}
$obj = [Ordered]@{
Long = [LongEnum]::LongValue
ULong = [ULongEnum]::ULongValue
}
$actual = ConvertTo-Json -InputObject $obj -Compress
$actual | Should -Be '{"Long":-1,"ULong":18446744073709551615}'
$actual = ConvertTo-Json -InputObject $obj -EnumsAsStrings -Compress
$actual | Should -Be '{"Long":"LongValue","ULong":"ULongValue"}'
}
}

View File

@@ -58,7 +58,9 @@ Describe "Json Tests" -Tags "Feature" {
$valueFromNotCompressedResult.FirstName | Should -Match $valueFromCompressedResult.FirstName $valueFromNotCompressedResult.FirstName | Should -Match $valueFromCompressedResult.FirstName
} }
It "Convertto-Json should handle Enum based on Int64" { It "Convertto-Json should handle Enum based on Int64" -Skip:(
[ExperimentalFeature]::IsEnabled("PSSerializeJSONLongEnumAsNumber")
) {
# Test follow-up for bug Win8: 378368 Convertto-Json problems with Enum based on Int64. # Test follow-up for bug Win8: 378368 Convertto-Json problems with Enum based on Int64.
if ( $null -eq ("JsonEnumTest" -as "Type")) { if ( $null -eq ("JsonEnumTest" -as "Type")) {
@@ -355,7 +357,7 @@ Describe "Json Tests" -Tags "Feature" {
{ {
"date-s-should-parse-as-datetime": "2008-09-22T14:01:54", "date-s-should-parse-as-datetime": "2008-09-22T14:01:54",
"date-upperO-should-parse-as-datetime": "2008-09-22T14:01:54.9571247Z", "date-upperO-should-parse-as-datetime": "2008-09-22T14:01:54.9571247Z",
"date-o-should-parse-as-string": "2019-12-17T06:14:06 +06:00", "date-o-should-parse-as-string": "2019-12-17T06:14:06 +06:00",
"date-upperD-should-parse-as-string": "Monday, September 22, 2008", "date-upperD-should-parse-as-string": "Monday, September 22, 2008",
"date-f-should-parse-as-string": "Monday, September 22, 2008 2:01 PM", "date-f-should-parse-as-string": "Monday, September 22, 2008 2:01 PM",
@@ -399,7 +401,7 @@ Describe "Json Tests" -Tags "Feature" {
$result."date-s-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008" $result."date-s-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008"
$result."date-s-should-parse-as-datetime".ToString("y") | Should -Be "September 2008" $result."date-s-should-parse-as-datetime".ToString("y") | Should -Be "September 2008"
$result."date-s-should-parse-as-datetime" | Should -BeOfType [DateTime] $result."date-s-should-parse-as-datetime" | Should -BeOfType [DateTime]
$result."date-upperO-should-parse-as-datetime" = [datetime]::SpecifyKind($result."date-upperO-should-parse-as-datetime", [System.DateTimeKind]::Utc) $result."date-upperO-should-parse-as-datetime" = [datetime]::SpecifyKind($result."date-upperO-should-parse-as-datetime", [System.DateTimeKind]::Utc)
$result."date-upperO-should-parse-as-datetime".ToString("d") | Should -Be "9/22/2008" $result."date-upperO-should-parse-as-datetime".ToString("d") | Should -Be "9/22/2008"
$result."date-upperO-should-parse-as-datetime".ToString("D") | Should -Be "Monday, September 22, 2008" $result."date-upperO-should-parse-as-datetime".ToString("D") | Should -Be "Monday, September 22, 2008"
@@ -420,7 +422,7 @@ Describe "Json Tests" -Tags "Feature" {
$result."date-upperO-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008" $result."date-upperO-should-parse-as-datetime".ToString("Y") | Should -Be "September 2008"
$result."date-upperO-should-parse-as-datetime".ToString("y") | Should -Be "September 2008" $result."date-upperO-should-parse-as-datetime".ToString("y") | Should -Be "September 2008"
$result."date-upperO-should-parse-as-datetime" | Should -BeOfType [DateTime] $result."date-upperO-should-parse-as-datetime" | Should -BeOfType [DateTime]
$result."date-o-should-parse-as-string" | Should -Be "2019-12-17T06:14:06 +06:00" $result."date-o-should-parse-as-string" | Should -Be "2019-12-17T06:14:06 +06:00"
$result."date-o-should-parse-as-string" | Should -BeOfType [String] $result."date-o-should-parse-as-string" | Should -BeOfType [String]
$result."date-f-should-parse-as-string" | Should -Be "Monday, September 22, 2008 2:01 PM" $result."date-f-should-parse-as-string" | Should -Be "Monday, September 22, 2008 2:01 PM"
@@ -453,7 +455,7 @@ Describe "Json Tests" -Tags "Feature" {
$result."date-y-should-parse-as-string" | Should -BeOfType [String] $result."date-y-should-parse-as-string" | Should -BeOfType [String]
} }
} }
It "ConvertFrom-Json properly parses complex objects" { It "ConvertFrom-Json properly parses complex objects" {
$json = @" $json = @"
{ {
@@ -541,13 +543,13 @@ Describe "Json Tests" -Tags "Feature" {
$result."registered" | Should -BeOfType [String] $result."registered" | Should -BeOfType [String]
$result."_id"| Should -BeExactly "60dd3ea9253016932039a0a2" $result."_id"| Should -BeExactly "60dd3ea9253016932039a0a2"
$result."_id" | Should -BeOfType [String] $result."_id" | Should -BeOfType [String]
$result.Tags | Should -BeOfType [string] $result.Tags | Should -BeOfType [string]
$result.Tags.count | Should -Be 7 $result.Tags.count | Should -Be 7
$result.Tags[0] | Should -BeExactly "laboris" $result.Tags[0] | Should -BeExactly "laboris"
$result.Tags | Should -Be @("laboris", "voluptate", "amet", "ad", "velit", "ipsum", "do") $result.Tags | Should -Be @("laboris", "voluptate", "amet", "ad", "velit", "ipsum", "do")
$result.Friends | Should -BeOfType [pscustomobject] $result.Friends | Should -BeOfType [pscustomobject]
$result.Friends[0].id | Should -Be 0 $result.Friends[0].id | Should -Be 0
$result.Friends[0].name | Should -BeExactly "Renee Holden" $result.Friends[0].name | Should -BeExactly "Renee Holden"
@@ -556,7 +558,7 @@ Describe "Json Tests" -Tags "Feature" {
$result.Friends[2].id | Should -Be 2 $result.Friends[2].id | Should -Be 2
$result.Friends[2].name | Should -BeExactly "Emilia Holder" $result.Friends[2].name | Should -BeExactly "Emilia Holder"
} }
It "ConvertFrom-Json chooses the appropriate number type" { It "ConvertFrom-Json chooses the appropriate number type" {
ConvertFrom-Json -InputObject "5" | should -Be 5 ConvertFrom-Json -InputObject "5" | should -Be 5
ConvertFrom-Json -InputObject 5 | should -Be 5 ConvertFrom-Json -InputObject 5 | should -Be 5
@@ -570,33 +572,33 @@ Describe "Json Tests" -Tags "Feature" {
ConvertFrom-Json -InputObject 5.0 | should -Be 5.0 ConvertFrom-Json -InputObject 5.0 | should -Be 5.0
ConvertFrom-Json -InputObject "5.0" | should -BeOfType [double] ConvertFrom-Json -InputObject "5.0" | should -BeOfType [double]
ConvertFrom-Json -InputObject 5.0 | should -BeOfType [double] ConvertFrom-Json -InputObject 5.0 | should -BeOfType [double]
# The decimal is lost but only when this is quoted # The decimal is lost but only when this is quoted
ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -Be "500000000000" ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -Be "500000000000"
# Counter intuitively all four of these tests pass because precision is lost on both sides of the test, likely due to powershell number handling # Counter intuitively all four of these tests pass because precision is lost on both sides of the test, likely due to powershell number handling
ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000 ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000
ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000.0000000000000001 ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -Be 500000000000.0000000000000001
ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000.0000000000000001 ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000.0000000000000001
ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000 ConvertFrom-Json -InputObject 500000000000 | should -Be 500000000000
ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -BeOfType [double] ConvertFrom-Json -InputObject "500000000000.0000000000000001" | should -BeOfType [double]
ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -BeOfType [double] ConvertFrom-Json -InputObject 500000000000.0000000000000001 | should -BeOfType [double]
# these tests also pass because precision is lost during conversion/powershell handling # these tests also pass because precision is lost during conversion/powershell handling
ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -Be "5E+34" ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -Be "5E+34"
ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -Be "5E+34" ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -Be "5E+34"
ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -BeOfType [double] ConvertFrom-Json -InputObject "50000000000000000000000000000000000.0000000000000001" | should -BeOfType [double]
ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -BeOfType [double] ConvertFrom-Json -InputObject 50000000000000000000000000000000000.0000000000000001 | should -BeOfType [double]
ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -Be 50000000000000000000000000000000000 ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -Be 50000000000000000000000000000000000
ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -Be 50000000000000000000000000000000000 ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -Be 50000000000000000000000000000000000
ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -BeOfType [BigInt] ConvertFrom-Json -InputObject "50000000000000000000000000000000000" | should -BeOfType [BigInt]
ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -BeOfType [BigInt] ConvertFrom-Json -InputObject 50000000000000000000000000000000000 | should -BeOfType [BigInt]
} }
It "ConvertFrom-Json with special characters" { It "ConvertFrom-Json with special characters" {
$json = '{"SampleValue":"\"\\\b\f\n\r\t\u4321\uD7FF"}' $json = '{"SampleValue":"\"\\\b\f\n\r\t\u4321\uD7FF"}'

View File

@@ -3,6 +3,7 @@
"ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ],
"PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ], "PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ],
"Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/RunspaceBreakpointManagement.Tests.ps1" ], "Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/RunspaceBreakpointManagement.Tests.ps1" ],
"PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ] "PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ],
"PSSerializeJSONLongEnumAsNumber": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1" ]
} }
} }