From 658883a450c874f46dcd920abb5dfed05a6a0a05 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Sat, 18 Feb 2017 18:39:25 -0800 Subject: [PATCH 1/6] Fix casting single element array to generic collection --- .../engine/LanguagePrimitives.cs | 12 +++--- .../Language/Parser/Conversions.Tests.ps1 | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs index 30b7dd26660..eb44031531c 100644 --- a/src/System.Management.Automation/engine/LanguagePrimitives.cs +++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs @@ -3581,20 +3581,20 @@ internal object Convert(object valueToConvert, TypeTable backupTable) { IList resultAsList = null; - int listSize = 0; Array array = null; try { - // typeof(Array).IsAssignableFrom(typeof(object[])) == true - if ((IsScalar) || (!(valueToConvert is Array))) + int listSize = 0; + if (IsScalar) { listSize = 1; } else { - array = (Array)valueToConvert; - listSize = array.Length; + // typeof(Array).IsAssignableFrom(typeof(object[])) == true + array = valueToConvert as Array; + listSize = array != null ? array.Length : 1; } resultAsList = ListCtorLambda(listSize); @@ -3610,7 +3610,7 @@ internal object Convert(object valueToConvert, { resultAsList.Add(valueToConvert); } - else if (listSize == 1) + else if (array == null) { object convertedValue = LanguagePrimitives.ConvertTo(valueToConvert, ElementType, formatProvider); resultAsList.Add(convertedValue); diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index 37efea9cfad..a970f267745 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -20,4 +20,41 @@ Describe 'conversion syntax' -Tags "CI" { # This test relies on the fact that there are overloads (at least 2) for ToString method. ([System.Management.Automation.ActionPreference]"Stop").ToString() | Should Be "Stop" } + + Context "Cast object[] to more narrow generic collection" { + BeforeAll { + $testCases = @( + @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 1; Elements = @(1) } + @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 2; Elements = @(1,2) } + @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 1; Elements = @(4) } + @{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Count = 1; Elements = @("1") } + @{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Count = 2; Elements = @("1","2") } + @{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Count = 1; Elements = @("1") } + + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 1; Elements = @(1) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 2; Elements = @(1,2) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 1; Elements = @(4) } + ) + } + + It "" -TestCases $testCases { + param($Command, $CollectionType, $ElementType, $Count, $Elements) + + $result = $null + . $Command + + $result | Should Not BeNullOrEmpty + $result.GetType().Name | Should Be $CollectionType + + $genericArgs = $result.GetType().GetGenericArguments() + $genericArgs.Length | Should Be 1 + $genericArgs[0].Name | Should Be $ElementType + + $result.Count | Should Be $Count + for ($i = 0; $i -lt $Count; $i++) + { + $result[$i] | Should Be $Elements[$i] + } + } + } } From b8cf316fd8e7c153a2c6d16222cdda4f5bd96851 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 20 Feb 2017 15:17:56 -0800 Subject: [PATCH 2/6] Fix comments in tests --- .../Language/Parser/Conversions.Tests.ps1 | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index a970f267745..e959bb463f2 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -23,22 +23,33 @@ Describe 'conversion syntax' -Tags "CI" { Context "Cast object[] to more narrow generic collection" { BeforeAll { - $testCases = @( - @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 1; Elements = @(1) } - @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 2; Elements = @(1,2) } - @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Count = 1; Elements = @(4) } - @{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Count = 1; Elements = @("1") } - @{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Count = 2; Elements = @("1","2") } - @{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Count = 1; Elements = @("1") } - - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 1; Elements = @(1) } - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 2; Elements = @(1,2) } - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Count = 1; Elements = @(4) } + $testCases1 = @( + @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1) } + @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1,2) } + @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4) } + @{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } + @{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1","2") } + @{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } + + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1,2) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4) } + ) + + $testCases2 = @( + @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile')}; + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } + + @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile1', 'TestFile2')}; + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile1', 'TestFile2') } + + @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]'TestFile'}; + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } ) } - It "" -TestCases $testCases { - param($Command, $CollectionType, $ElementType, $Count, $Elements) + It "" -TestCases $testCases1 { + param($Command, $CollectionType, $ElementType, $Elements) $result = $null . $Command @@ -50,11 +61,31 @@ Describe 'conversion syntax' -Tags "CI" { $genericArgs.Length | Should Be 1 $genericArgs[0].Name | Should Be $ElementType - $result.Count | Should Be $Count - for ($i = 0; $i -lt $Count; $i++) + $result.Count | Should Be $Elements.Length + for ($i=0; $i -lt $Elements.Length; $i++) { $result[$i] | Should Be $Elements[$i] } } + + It "" -TestCases $testCases2 { + param($Command, $CollectionType, $ElementType, $Elements) + + $result = $null + . $Command + + $result | Should Not BeNullOrEmpty + $result.GetType().Name | Should Be $CollectionType + + $genericArgs = $result.GetType().GetGenericArguments() + $genericArgs.Length | Should Be 1 + $genericArgs[0].Name | Should Be $ElementType + + $result.Count | Should Be $Elements.Length + for ($i=0; $i -lt $Elements.Length; $i++) + { + $result[$i].Name | Should Be $Elements[$i] + } + } } } From 7531634abc6ca29e2755eb36ee546ee5be3bd823 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 20 Feb 2017 15:30:55 -0800 Subject: [PATCH 3/6] Fix the test a bit more --- .../Language/Parser/Conversions.Tests.ps1 | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index e959bb463f2..ebbd65e331d 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -38,13 +38,11 @@ Describe 'conversion syntax' -Tags "CI" { $testCases2 = @( @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile')}; - CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } - + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile1', 'TestFile2')}; - CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile1', 'TestFile2') } - + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile1', 'TestFile2') } @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]'TestFile'}; - CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } + CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } ) } @@ -62,10 +60,7 @@ Describe 'conversion syntax' -Tags "CI" { $genericArgs[0].Name | Should Be $ElementType $result.Count | Should Be $Elements.Length - for ($i=0; $i -lt $Elements.Length; $i++) - { - $result[$i] | Should Be $Elements[$i] - } + $result -join ";" | Should Be ($Elements -join ";") } It "" -TestCases $testCases2 { @@ -82,10 +77,7 @@ Describe 'conversion syntax' -Tags "CI" { $genericArgs[0].Name | Should Be $ElementType $result.Count | Should Be $Elements.Length - for ($i=0; $i -lt $Elements.Length; $i++) - { - $result[$i].Name | Should Be $Elements[$i] - } + @($result.Name) -join ";" | Should Be ($Elements -join ";") } } } From 8d0907c708bf5510d766cc6af94944aa2e5a3d54 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 21 Feb 2017 09:06:27 -0800 Subject: [PATCH 4/6] One more fix in the test --- .../Language/Parser/Conversions.Tests.ps1 | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index ebbd65e331d..5be5fcff104 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -34,9 +34,7 @@ Describe 'conversion syntax' -Tags "CI" { @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1) } @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1,2) } @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4) } - ) - $testCases2 = @( @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile')}; CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile1', 'TestFile2')}; @@ -62,22 +60,5 @@ Describe 'conversion syntax' -Tags "CI" { $result.Count | Should Be $Elements.Length $result -join ";" | Should Be ($Elements -join ";") } - - It "" -TestCases $testCases2 { - param($Command, $CollectionType, $ElementType, $Elements) - - $result = $null - . $Command - - $result | Should Not BeNullOrEmpty - $result.GetType().Name | Should Be $CollectionType - - $genericArgs = $result.GetType().GetGenericArguments() - $genericArgs.Length | Should Be 1 - $genericArgs[0].Name | Should Be $ElementType - - $result.Count | Should Be $Elements.Length - @($result.Name) -join ";" | Should Be ($Elements -join ";") - } } } From eed79d109dd32cfbc0cae83d98afa388e39fe1e4 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 22 Feb 2017 13:28:16 -0800 Subject: [PATCH 5/6] add test for casting array with more than 1 string elements --- .../Language/Parser/Conversions.Tests.ps1 | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index 5be5fcff104..5bac3b0cea7 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -24,16 +24,20 @@ Describe 'conversion syntax' -Tags "CI" { Context "Cast object[] to more narrow generic collection" { BeforeAll { $testCases1 = @( - @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1) } - @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1,2) } - @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4) } - @{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } - @{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1","2") } - @{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } + @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1) } + @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1,2) } + @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4) } + @{ Command = {$result = [Collections.Generic.List[int]]@("4","5")}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4,5) } - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1) } - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1,2) } - @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4) } + @{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } + @{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1","2") } + @{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") } + @{ Command = {$result = [Collections.Generic.List[string]]@("4")}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("4") } + + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1,2) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4) } + @{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@("4","5")}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4,5) } @{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile')}; CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') } From d0585133d41913f8de92d8945636c9a80ba86c45 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 22 Feb 2017 15:15:52 -0800 Subject: [PATCH 6/6] Add a comment --- test/powershell/Language/Parser/Conversions.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/powershell/Language/Parser/Conversions.Tests.ps1 b/test/powershell/Language/Parser/Conversions.Tests.ps1 index 5bac3b0cea7..6aca007f90a 100644 --- a/test/powershell/Language/Parser/Conversions.Tests.ps1 +++ b/test/powershell/Language/Parser/Conversions.Tests.ps1 @@ -24,6 +24,13 @@ Describe 'conversion syntax' -Tags "CI" { Context "Cast object[] to more narrow generic collection" { BeforeAll { $testCases1 = @( + ## It's intentional to have 'Command' to be `{$result = ...}` and run it with `. $Command`. + ## This is because `$result = & {[List[int]]@(1,2)}` will cause the resulted List to be unraveled, + ## and in that case `$result` would be just an object array. + ## To prevent unraveling, Command needs to be `{, [List[int]]@(1,2)}`, but then the test case title + ## would become `, [List[int]]@(1,2)`, which is more confusing than `$result = [List[int]]@(1,2)`. + ## This is why the current form of `$result = [List[int]]@(1,2)` is used intentionally here. + @{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1) } @{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1,2) } @{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4) }