From 8f421700156786e15c73c9e2f119cd4a1d71db21 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 17 Dec 2019 12:30:39 -0800 Subject: [PATCH 1/4] Make null member access tests as string to avoid parsing errors --- .../Operators/NullConditional.Tests.ps1 | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/powershell/Language/Operators/NullConditional.Tests.ps1 b/test/powershell/Language/Operators/NullConditional.Tests.ps1 index 97dbc32e1ad..3bb2140271d 100644 --- a/test/powershell/Language/Operators/NullConditional.Tests.ps1 +++ b/test/powershell/Language/Operators/NullConditional.Tests.ps1 @@ -260,6 +260,15 @@ Describe 'NullConditionalMemberAccess' -Tag 'CI' { $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = $true } + + function ExecuteTestIfFeatureIsEnabled([string] $TestContet) + { + if ($skipTest) { + Set-ItResult -Skipped -Because "PSNullConditionalOperators feature is disabled" + } else { + Invoke-Expression $testContent + } + } } AfterAll { @@ -285,6 +294,8 @@ Describe 'NullConditionalMemberAccess' -Tag 'CI' { } It 'Can get member value of a non-null variable' { + + $testContent = @' ${psObj}?.name | Should -BeExactly 'value' ${array}?.length | Should -Be 3 ${hash}?.a | Should -Be 1 @@ -293,50 +304,81 @@ Describe 'NullConditionalMemberAccess' -Tag 'CI' { (Get-Item $TestDrive)?.EnumerateFiles()?.Name | Should -BeExactly 'testfile.txt' [int32]::MaxValue?.ToString() | Should -BeExactly '2147483647' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Can get null when variable is null' { + $testContent = @' ${nonExistent}?.name | Should -BeNullOrEmpty ${nonExistent}?.MyMethod() | Should -BeNullOrEmpty (get-process -Name doesnotexist -ErrorAction SilentlyContinue)?.Id | Should -BeNullOrEmpty +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Use ?. operator multiple times in statement' { + $testContent = @' ${psObj}?.name?.nonExistent | Should -BeNullOrEmpty ${psObj}?.nonExistent?.nonExistent | Should -BeNullOrEmpty ${nonExistent}?.nonExistent?.nonExistent | Should -BeNullOrEmpty ${psObj}?.nested?.name | Should -BeExactly 'valuenested' ${psObj}?.nestedMethod?.GetHello() | Should -BeExactly 'hello' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Use ?. on a dynamic method name' { + $testContent = @' $methodName = 'ToLongDateString' (Get-Date '11/11/2019')?.$methodName() | Should -BeExactly 'Monday, November 11, 2019' ${doesNotExist}?.$methodName() | Should -BeNullOrEmpty +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Use ?. on a dynamic method name that does not exist' { + $testContent = @' $methodName = 'DoesNotExist' { (Get-Date '11/11/2019')?.$methodName() } | Should -Throw -ErrorId 'MethodNotFound' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Use ?. on a dynamic method name that does not exist' { + $testContent = @' $methodName = $null { (Get-Date '11/11/2019')?.$methodName() } | Should -Throw -ErrorId 'MethodNotFound' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Use ?. on a dynamic property name' { + $testContent = @' $propName = 'Name' (Get-Process -Id $pid)?.$propName | Should -BeLike 'pwsh*' ${doesNotExist}?.$propName() | Should -BeNullOrEmpty +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Should throw error when method does not exist' { + $testContent = @' { ${psObj}?.nestedMethod?.NonExistent() } | Should -Throw -ErrorId 'MethodNotFound' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } } @@ -352,30 +394,46 @@ Describe 'NullConditionalMemberAccess' -Tag 'CI' { } It 'Can index can call properties' { + $testContent = @' ${array}?[0] | Should -Be 1 ${array}?[0,1] | Should -Be @(1,2) ${array}?[0..2] | Should -Be @(1,2,3) ${array}?[-2] | Should -Be 2 ${hash}?['a'] | Should -Be 1 +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Indexing in null items should be null' { + $testContent = @' ${doesnotExist}?[0] | Should -BeNullOrEmpty ${doesnotExist}?[0,1] | Should -BeNullOrEmpty ${doesnotExist}?[0..2] | Should -BeNullOrEmpty ${doesnotExist}?[-2] | Should -BeNullOrEmpty ${doesnotExist}?['a'] | Should -BeNullOrEmpty +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Can call methods on indexed items' { + $testContent = @' ${dateArray}?[0]?.ToLongDateString() | Should -BeExactly 'Friday, November 1, 2019' +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } It 'Calling a method on nonexistent item give null' { + $testContent = @' ${dateArray}?[1234]?.ToLongDateString() | Should -BeNullOrEmpty ${doesNotExist}?[0]?.MyGetMethod() | Should -BeNullOrEmpty +'@ + + ExecuteTestIfFeatureIsEnabled -TestContent $testContent } } } From a8cee1095cf3ed73d77ad5e5c55a8244f6f89585 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Dec 2019 13:59:13 -0800 Subject: [PATCH 2/4] Add PSNullConditionalOperators feature to testmetadata.json --- test/tools/TestMetadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index c49ab1758c6..b80656b0ba7 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -1,5 +1,6 @@ { "ExperimentalFeatures": { - "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ] + "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], + "PSNullConditionalOperators": [ "test/powershell/Language/Operators/NullConditional.Tests.ps1" ] } } From 6c73bca2945c30a29fd477407409c662c5ec8d84 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Dec 2019 14:30:54 -0800 Subject: [PATCH 3/4] Add Parsing tests to be skipped --- .../Language/Parser/Parsing.Tests.ps1 | 27 ++++++++++--------- test/tools/TestMetadata.json | 4 ++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/test/powershell/Language/Parser/Parsing.Tests.ps1 b/test/powershell/Language/Parser/Parsing.Tests.ps1 index 870df2c2561..3b3e49d9f05 100644 --- a/test/powershell/Language/Parser/Parsing.Tests.ps1 +++ b/test/powershell/Language/Parser/Parsing.Tests.ps1 @@ -295,18 +295,21 @@ Describe 'null conditional member access statement parsing' -Tag 'CI' { } } - ShouldBeParseError '[datetime]?::now' ExpectedValueExpression,UnexpectedToken 11,11 - ShouldBeParseError '$x ?.name' ExpectedValueExpression,UnexpectedToken 4,4 - ShouldBeParseError 'Get-Date ?.ToString()' ExpectedExpression 20 - ShouldBeParseError '${x}?.' MissingPropertyName 6 - ShouldBeParseError '${x}?.name = "value"' InvalidLeftHandSide 0 - - ShouldBeParseError '[datetime]?[0]' MissingTypename,ExpectedValueExpression,UnexpectedToken 12,11,11 - ShouldBeParseError '${x} ?[1]' MissingTypename,ExpectedValueExpression,UnexpectedToken 7,6,6 - ShouldBeParseError '${x}?[]' MissingArrayIndexExpression 6 - ShouldBeParseError '${x}?[-]' MissingExpressionAfterOperator 7 - ShouldBeParseError '${x}?[ ]' MissingArrayIndexExpression 6 - ShouldBeParseError '${x}?[0] = 1' InvalidLeftHandSide 0 + # We need to add this check as parsing on script block is done before an `It` is called. + if (-not $skipTest) { + ShouldBeParseError '[datetime]?::now' ExpectedValueExpression, UnexpectedToken 11, 11 + ShouldBeParseError '$x ?.name' ExpectedValueExpression, UnexpectedToken 4, 4 + ShouldBeParseError 'Get-Date ?.ToString()' ExpectedExpression 20 + ShouldBeParseError '${x}?.' MissingPropertyName 6 + ShouldBeParseError '${x}?.name = "value"' InvalidLeftHandSide 0 + + ShouldBeParseError '[datetime]?[0]' MissingTypename, ExpectedValueExpression, UnexpectedToken 12, 11, 11 + ShouldBeParseError '${x} ?[1]' MissingTypename, ExpectedValueExpression, UnexpectedToken 7, 6, 6 + ShouldBeParseError '${x}?[]' MissingArrayIndexExpression 6 + ShouldBeParseError '${x}?[-]' MissingExpressionAfterOperator 7 + ShouldBeParseError '${x}?[ ]' MissingArrayIndexExpression 6 + ShouldBeParseError '${x}?[0] = 1' InvalidLeftHandSide 0 + } } Describe 'splatting parsing' -Tags "CI" { diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index b80656b0ba7..37ace18d41c 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -1,6 +1,8 @@ { "ExperimentalFeatures": { "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], - "PSNullConditionalOperators": [ "test/powershell/Language/Operators/NullConditional.Tests.ps1" ] + "PSNullConditionalOperators": [ + "test/powershell/Language/Operators/NullConditional.Tests.ps1", + "test/powershell/Language/Parser/Parsing.Tests.ps1" ] } } From e9bfd1a7feaf05b1aba7b85f886183722b805939 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 20 Dec 2019 15:51:48 -0800 Subject: [PATCH 4/4] Add tabcompletion tests --- test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 | 5 +++-- test/tools/TestMetadata.json | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index de231bd8e81..44b56cb405a 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -3,6 +3,7 @@ Describe "TabCompletion" -Tags CI { BeforeAll { $separator = [System.IO.Path]::DirectorySeparatorChar + $nullConditionalFeatureDisabled = -not $EnabledExperimentalFeatures.Contains('PSNullConditionalOperators') } It 'Should complete Command' { @@ -33,12 +34,12 @@ Describe "TabCompletion" -Tags CI { $res.CompletionMatches[0].CompletionText | Should -BeExactly 'ToString(' } - It 'Should complete dotnet method with null conditional operator' { + It 'Should complete dotnet method with null conditional operator' -skip:$nullConditionalFeatureDisabled { $res = TabExpansion2 -inputScript '(1)?.ToSt' -cursorColumn '(1)?.ToSt'.Length $res.CompletionMatches[0].CompletionText | Should -BeExactly 'ToString(' } - It 'Should complete dotnet method with null conditional operator without first letter' { + It 'Should complete dotnet method with null conditional operator without first letter' -skip:$nullConditionalFeatureDisabled { $res = TabExpansion2 -inputScript '(1)?.' -cursorColumn '(1)?.'.Length $res.CompletionMatches[0].CompletionText | Should -BeExactly 'CompareTo(' } diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index e2c43f81efa..f8439ced074 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -3,7 +3,8 @@ "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], "PSNullConditionalOperators": [ "test/powershell/Language/Operators/NullConditional.Tests.ps1", - "test/powershell/Language/Parser/Parsing.Tests.ps1" ], + "test/powershell/Language/Parser/Parsing.Tests.ps1", + "/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1" ], "PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ] } }