Skip to content

Commit 6984cf3

Browse files
committed
Fix Version scalar type handling and cross-platform test issues
1 parent 9b84e8c commit 6984cf3

3 files changed

Lines changed: 68 additions & 5 deletions

File tree

src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommandV2.cs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,13 @@ public override bool CanConvert(Type typeToConvert)
915915
typeToConvert != typeof(Newtonsoft.Json.Linq.JObject),
916916
$"Type {typeToConvert} should be handled by its dedicated converter");
917917

918+
// Version: STJ treats as scalar (Kind=None) and serializes as string.
919+
// Serialize as object with properties instead.
920+
if (typeToConvert == typeof(Version))
921+
{
922+
return true;
923+
}
924+
918925
// Check if STJ handles this type as a scalar
919926
var typeInfo = JsonSerializerOptions.Default.GetTypeInfo(typeToConvert);
920927
return typeInfo.Kind != JsonTypeInfoKind.None;
@@ -1066,9 +1073,25 @@ public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOp
10661073

10671074
// Use JsonTypeInfo to enumerate properties - leverages STJ caching and handles JsonIgnore automatically
10681075
var typeInfo = JsonSerializerOptions.Default.GetTypeInfo(value.GetType());
1069-
foreach (var propInfo in typeInfo.Properties)
1076+
if (typeInfo.Properties.Count > 0)
10701077
{
1071-
WriteProperty(writer, value, propInfo, options);
1078+
foreach (var propInfo in typeInfo.Properties)
1079+
{
1080+
WriteProperty(writer, value, propInfo, options);
1081+
}
1082+
}
1083+
else
1084+
{
1085+
// Fallback for types like Version where STJ treats as scalar (Kind=None)
1086+
// Use PSObject Adapted properties to enumerate via reflection
1087+
var pso = PSObject.AsPSObject(value);
1088+
foreach (var prop in pso.Properties)
1089+
{
1090+
if (prop.MemberType == PSMemberTypes.Property)
1091+
{
1092+
WriteAdaptedProperty(writer, value, prop, options);
1093+
}
1094+
}
10721095
}
10731096

10741097
writer.WriteEndObject();
@@ -1105,6 +1128,31 @@ private void WriteProperty(Utf8JsonWriter writer, object obj, JsonPropertyInfo p
11051128
JsonSerializerHelper.WriteValue(writer, value, options);
11061129
}
11071130
}
1131+
1132+
private void WriteAdaptedProperty(Utf8JsonWriter writer, object obj, PSPropertyInfo prop, JsonSerializerOptions options)
1133+
{
1134+
object? value = null;
1135+
try
1136+
{
1137+
value = prop.Value;
1138+
}
1139+
catch
1140+
{
1141+
// Property access threw - value remains null
1142+
}
1143+
1144+
writer.WritePropertyName(prop.Name);
1145+
1146+
// If maxDepth is 0 and value is non-null non-scalar, convert to string
1147+
if (_cmdlet.Depth == 0 && value is not null && !JsonSerializerHelper.IsStjNativeScalarType(value))
1148+
{
1149+
writer.WriteStringValue(value.ToString());
1150+
}
1151+
else
1152+
{
1153+
JsonSerializerHelper.WriteValue(writer, value, options);
1154+
}
1155+
}
11081156
}
11091157

11101158
/// <summary>
@@ -1136,6 +1184,12 @@ public static bool IsStjNativeScalarType(object obj)
11361184
return false;
11371185
}
11381186

1187+
// Version: STJ treats as scalar (Kind=None) but V1 serializes as object with properties.
1188+
if (type == typeof(Version))
1189+
{
1190+
return false;
1191+
}
1192+
11391193
// GetTypeInfo() has internal caching, no need for additional cache
11401194
var typeInfo = JsonSerializerOptions.Default.GetTypeInfo(type);
11411195
return typeInfo.Kind == JsonTypeInfoKind.None;

test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ Describe 'ConvertTo-Json' -tags "CI" {
327327
$json = $arr | ConvertTo-Json -Depth 2
328328
$parsed = $json | ConvertFrom-Json
329329

330-
$parsed[0].PSObject.Properties.Name.Count | Should -Be 24
330+
# Windows has 24 Adapted properties, Unix has 28 (includes Unix-specific file properties)
331+
$expectedCount = if ($IsWindows) { 24 } else { 28 }
332+
$parsed[0].PSObject.Properties.Name.Count | Should -Be $expectedCount
331333
}
332334

333335
It 'Array of Get-Item FileInfo preserves Extended properties' {
@@ -429,7 +431,7 @@ Describe 'ConvertTo-Json' -tags "CI" {
429431
}
430432

431433
It 'Non-pure PSObject (FileInfo) with ETS properties includes ETS when depth exceeded' {
432-
$file = Get-Item $PSHOME/pwsh.exe
434+
$file = Get-Item (Join-Path $PSHOME 'System.Management.Automation.dll')
433435
$pso = [PSObject]::new($file)
434436
$pso | Add-Member -NotePropertyName CustomExt -NotePropertyValue 'extended_value'
435437
$outer = [PSCustomObject]@{ File = $pso }
@@ -438,7 +440,7 @@ Describe 'ConvertTo-Json' -tags "CI" {
438440
$parsed = $result | ConvertFrom-Json
439441

440442
$parsed.File.CustomExt | Should -BeExactly 'extended_value'
441-
$parsed.File.value | Should -BeLike '*pwsh.exe'
443+
$parsed.File.value | Should -BeLike '*System.Management.Automation.dll'
442444
}
443445

444446
}

test/powershell/Modules/Microsoft.PowerShell.Utility/Json.Tests.ps1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ Describe "Json Tests" -Tags "Feature" {
355355
# For the ones that are datetimes, make sure they retain all of the various formats correctly
356356
# for the ones that are strings just verify that they are actually strings.
357357

358+
# Use en-US culture to ensure consistent date format output across all environments
359+
$originalCulture = [Threading.Thread]::CurrentThread.CurrentCulture
360+
[Threading.Thread]::CurrentThread.CurrentCulture = [CultureInfo]::new('en-US')
361+
try {
358362
$json = @"
359363
{
360364
"date-s-should-parse-as-datetime": "2008-09-22T14:01:54",
@@ -456,6 +460,9 @@ Describe "Json Tests" -Tags "Feature" {
456460
$result."date-y-should-parse-as-string" | Should -Be "September 2008"
457461
$result."date-y-should-parse-as-string" | Should -BeOfType [String]
458462
}
463+
} finally {
464+
[Threading.Thread]::CurrentThread.CurrentCulture = $originalCulture
465+
}
459466
}
460467

461468
It "ConvertFrom-Json properly parses complex objects" {

0 commit comments

Comments
 (0)