From 42cb8ba64361a06ca4d77cd750e1200c778a2faa Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 4 May 2017 10:33:52 +0600 Subject: [PATCH] Move 'PSVersion' and 'PSEdition' to first and second places in $PSVersionTable (#3562) --- .../engine/PSVersionInfo.cs | 82 ++++++++++++----- test/powershell/Host/PSVersionTable.Tests.ps1 | 90 ++++++++++++++++++- .../Variable.Tests.ps1 | 16 ---- 3 files changed, 147 insertions(+), 41 deletions(-) diff --git a/src/System.Management.Automation/engine/PSVersionInfo.cs b/src/System.Management.Automation/engine/PSVersionInfo.cs index daf8e8649c..95a3118177 100644 --- a/src/System.Management.Automation/engine/PSVersionInfo.cs +++ b/src/System.Management.Automation/engine/PSVersionInfo.cs @@ -19,6 +19,13 @@ namespace System.Management.Automation internal const string PSVersionTableName = "PSVersionTable"; internal const string PSRemotingProtocolVersionName = "PSRemotingProtocolVersion"; internal const string PSVersionName = "PSVersion"; + internal const string PSEditionName = "PSEdition"; + internal const string PSBuildVersionName = "BuildVersion"; + internal const string PSGitCommitIdName = "GitCommitId"; + internal const string PSCompatibleVersionsName = "PSCompatibleVersions"; + internal const string PSCLRVersionName = "CLRVersion"; + internal const string PSPlatformName = "Platform"; + internal const string PSOSName = "OS"; internal const string SerializationVersionName = "SerializationVersion"; internal const string WSManStackVersionName = "WSManStackVersion"; private static PSVersionHashTable s_psVersionTable = null; @@ -57,20 +64,20 @@ namespace System.Management.Automation s_psVersionTable = new PSVersionHashTable(StringComparer.OrdinalIgnoreCase); s_psVersionTable[PSVersionInfo.PSVersionName] = s_psV6Version; - s_psVersionTable["PSEdition"] = PSEditionValue; - s_psVersionTable["BuildVersion"] = GetBuildVersion(); - s_psVersionTable["GitCommitId"] = GetCommitInfo(); - s_psVersionTable["PSCompatibleVersions"] = new Version[] { s_psV1Version, s_psV2Version, s_psV3Version, s_psV4Version, s_psV5Version, s_psV51Version, s_psV6Version }; + s_psVersionTable[PSVersionInfo.PSEditionName] = PSEditionValue; + s_psVersionTable[PSBuildVersionName] = GetBuildVersion(); + s_psVersionTable[PSGitCommitIdName] = GetCommitInfo(); + s_psVersionTable[PSCompatibleVersionsName] = new Version[] { s_psV1Version, s_psV2Version, s_psV3Version, s_psV4Version, s_psV5Version, s_psV51Version, s_psV6Version }; s_psVersionTable[PSVersionInfo.SerializationVersionName] = new Version(InternalSerializer.DefaultVersion); s_psVersionTable[PSVersionInfo.PSRemotingProtocolVersionName] = RemotingConstants.ProtocolVersion; s_psVersionTable[PSVersionInfo.WSManStackVersionName] = GetWSManStackVersion(); - s_psVersionTable["Platform"] = Environment.OSVersion.Platform.ToString(); + s_psVersionTable[PSPlatformName] = Environment.OSVersion.Platform.ToString(); #if CORECLR - s_psVersionTable["OS"] = Runtime.InteropServices.RuntimeInformation.OSDescription.ToString(); - s_psVersionTable["CLRVersion"] = null; +            s_psVersionTable[PSCLRVersionName] = null; + s_psVersionTable[PSOSName] = Runtime.InteropServices.RuntimeInformation.OSDescription.ToString(); #else - s_psVersionTable["CLRVersion"] = Environment.Version; - s_psVersionTable["OS"] = Environment.OSVersion.ToString(); + s_psVersionTable[PSCLRVersionName] = Environment.Version; + s_psVersionTable[PSOSName] = Environment.OSVersion.ToString(); #endif } @@ -160,7 +167,7 @@ namespace System.Management.Automation { get { - return (string)GetPSVersionTable()["GitCommitId"]; + return (string)GetPSVersionTable()[PSGitCommitIdName]; } } @@ -168,7 +175,7 @@ namespace System.Management.Automation { get { - return (Version)GetPSVersionTable()["CLRVersion"]; + return (Version)GetPSVersionTable()[PSCLRVersionName]; } } @@ -176,7 +183,7 @@ namespace System.Management.Automation { get { - return (Version)GetPSVersionTable()["BuildVersion"]; + return (Version)GetPSVersionTable()[PSBuildVersionName]; } } @@ -184,7 +191,7 @@ namespace System.Management.Automation { get { - return (Version[])GetPSVersionTable()["PSCompatibleVersions"]; + return (Version[])GetPSVersionTable()[PSCompatibleVersionsName]; } } @@ -192,7 +199,7 @@ namespace System.Management.Automation { get { - return (string)GetPSVersionTable()["PSEdition"]; + return (string)GetPSVersionTable()[PSVersionInfo.PSEditionName]; } } @@ -200,7 +207,7 @@ namespace System.Management.Automation { get { - return (Version)GetPSVersionTable()["SerializationVersion"]; + return (Version)GetPSVersionTable()[SerializationVersionName]; } } @@ -324,21 +331,54 @@ namespace System.Management.Automation /// public sealed class PSVersionHashTable : Hashtable, IEnumerable { + private static readonly PSVersionTableComparer s_keysComparer = new PSVersionTableComparer(); internal PSVersionHashTable(IEqualityComparer equalityComparer) : base(equalityComparer) { } /// /// Returns ordered collection with Keys of 'PSVersionHashTable' + /// We want see special order: + /// 1. PSVersionName + /// 2. PSEditionName + /// 3. Remaining properties in alphabetical order /// public override ICollection Keys { get { - Array arr = new string[base.Keys.Count]; - base.Keys.CopyTo(arr, 0); - Array.Sort(arr, StringComparer.OrdinalIgnoreCase); - return arr; + ArrayList keyList = new ArrayList(base.Keys); + keyList.Sort(s_keysComparer); + return keyList; + } + } + + private class PSVersionTableComparer : IComparer + { + public int Compare(object x, object y) + { + string xString = (string)LanguagePrimitives.ConvertTo(x, typeof(string), CultureInfo.CurrentCulture); + string yString = (string)LanguagePrimitives.ConvertTo(y, typeof(string), CultureInfo.CurrentCulture); + if (PSVersionInfo.PSVersionName.Equals(xString, StringComparison.OrdinalIgnoreCase)) + { + return -1; + } + else if (PSVersionInfo.PSVersionName.Equals(yString, StringComparison.OrdinalIgnoreCase)) + { + return 1; + } + else if (PSVersionInfo.PSEditionName.Equals(xString, StringComparison.OrdinalIgnoreCase)) + { + return -1; + } + else if (PSVersionInfo.PSEditionName.Equals(yString, StringComparison.OrdinalIgnoreCase)) + { + return 1; + } + else + { + return String.Compare(xString, yString, StringComparison.OrdinalIgnoreCase); + } } } @@ -348,9 +388,9 @@ namespace System.Management.Automation /// IEnumerator IEnumerable.GetEnumerator() { - foreach (string key in Keys) + foreach (object key in Keys) { - yield return new System.Collections.DictionaryEntry(key, this[key]); + yield return new DictionaryEntry(key, this[key]); } } } diff --git a/test/powershell/Host/PSVersionTable.Tests.ps1 b/test/powershell/Host/PSVersionTable.Tests.ps1 index 78e3eb005d..e034b8f2d0 100644 --- a/test/powershell/Host/PSVersionTable.Tests.ps1 +++ b/test/powershell/Host/PSVersionTable.Tests.ps1 @@ -21,10 +21,6 @@ Describe "PSVersionTable" -Tags "CI" { $PSVersionTable.GitCommitId | Should not match "powershell.version" } - It "Should have the correct edition" -Skip:(!$IsCoreCLR) { - $PSVersionTable["PSEdition"] | Should Be "Core" - } - It "Should have the correct platform info" { $platform = [String][System.Environment]::OSVersion.Platform [String]$PSVersionTable["Platform"] | Should Be $platform @@ -42,4 +38,90 @@ Describe "PSVersionTable" -Tags "CI" { [String]$PSVersionTable["OS"] | Should Be $OSDescription } } + + It "Verify `$PSVersionTable.PSEdition" { + if ($isCoreCLR) { + $edition = "Core" + } + else + { + $edition = "Desktop" + } + $PSVersionTable["PSEdition"] | Should Be $edition + } + + It "Verify `$PSVersionTable is ordered and 'PSVersion' is on first place" { + $PSVersionName = "PSVersion" + $keys1 = ($PSVersionTable | Format-Table -HideTableHeaders -Property Name | Out-String) -split [System.Environment]::NewLine | Where-Object {$_} | ForEach-Object {$_.Trim()} + + $keys1[0] | Should Be "PSVersion" + $keys1[1] | Should Be "PSEdition" + + $keys1last = $keys1[2..($keys1.length-1)] + $keys1sortedlast = $keys1last | Sort-Object + + Compare-Object -ReferenceObject $keys1last -DifferenceObject $keys1sortedlast -SyncWindow 0 | Should Be $null + } + + It "Verify `$PSVersionTable can be formatted correctly when it has non-string key" { + try { + $key = Get-Item $PSScriptRoot + $PSVersionTable.Add($key, "TEST") + { $PSVersionTable | Format-Table } | Should Not Throw + } finally { + $PSVersionTable.Remove($key) + } + } + + It "Verify `$PSVersionTable can be formatted correctly when 'PSVersion' is removed" { + try { + $VersionValue = $PSVersionTable["PSVersion"] + $PSVersionTable.Remove("PSVersion") + + $keys1 = ($PSVersionTable | Format-Table -HideTableHeaders -Property Name | Out-String) -split [System.Environment]::NewLine | Where-Object {$_} | ForEach-Object {$_.Trim()} + $keys1[0] | Should Be "PSEdition" + $keys1.Length | Should Be $PSVersionTable.Count + + $keys1last = $keys1[1..($keys1.length-1)] + $keys1sortedlast = $keys1last | Sort-Object + Compare-Object -ReferenceObject $keys1last -DifferenceObject $keys1sortedlast -SyncWindow 0 | Should Be $null + } finally { + $PSVersionTable.Add("PSVersion", $VersionValue) + } + } + + It "Verify `$PSVersionTable can be formatted correctly when 'PSEdition' is removed" { + try { + $EditionValue = $PSVersionTable["PSEdition"] + $PSVersionTable.Remove("PSEdition") + + $keys1 = ($PSVersionTable | Format-Table -HideTableHeaders -Property Name | Out-String) -split [System.Environment]::NewLine | Where-Object {$_} | ForEach-Object {$_.Trim()} + $keys1[0] | Should Be "PSVersion" + $keys1.Length | Should Be $PSVersionTable.Count + + $keys1last = $keys1[1..($keys1.length-1)] + $keys1sortedlast = $keys1last | Sort-Object + Compare-Object -ReferenceObject $keys1last -DifferenceObject $keys1sortedlast -SyncWindow 0 | Should Be $null + } finally { + $PSVersionTable.Add("PSEdition", $EditionValue) + } + } + + It "Verify `$PSVersionTable can be formatted correctly when both 'PSEdition' and 'PSVersion' are removed" { + try { + $VersionValue = $PSVersionTable["PSVersion"] + $EditionValue = $PSVersionTable["PSEdition"] + $PSVersionTable.Remove("PSVersion") + $PSVersionTable.Remove("PSEdition") + + $keys1 = ($PSVersionTable | Format-Table -HideTableHeaders -Property Name | Out-String) -split [System.Environment]::NewLine | Where-Object {$_} | ForEach-Object {$_.Trim()} + $keys1.Length | Should Be $PSVersionTable.Count + + $keys1sortedlast = $keys1 | Sort-Object + Compare-Object -ReferenceObject $keys1 -DifferenceObject $keys1sortedlast -SyncWindow 0 | Should Be $null + } finally { + $PSVersionTable.Add("PSVersion", $VersionValue) + $PSVersionTable.Add("PSEdition", $EditionValue) + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Variable.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Variable.Tests.ps1 index 31bad4cf0e..38bb26c3ee 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Variable.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Variable.Tests.ps1 @@ -110,19 +110,3 @@ Describe "Validate basic negative test cases for Variable provider cmdlets" -Tag catch { $_.FullyQualifiedErrorId | Should be "NotSupported,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand" } } } - -Describe "Validate special variables" -Tags "CI" { - It "Verify `$PSVersionTable.PSEdition" { - $PSVersionTable["PSEdition"] | Should Be "Core" - } - - It "Verify `$PSVersionTable is ordered" { - $keys1 = $PSVersionTable.Keys - $keys1sorted = $keys1 | Sort-Object - $keys2 = ($PSVersionTable | Format-Table -HideTableHeaders -Property Name | Out-String) -split [System.Environment]::NewLine | Where-Object {$_} - $keys2sorted = $keys2 | Sort-Object - - Compare-Object -ReferenceObject $keys1 -DifferenceObject $keys1sorted -SyncWindow 0 | Should Be $null - Compare-Object -ReferenceObject $keys2 -DifferenceObject $keys2sorted -SyncWindow 0 | Should Be $null - } -}