mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-17 04:36:39 +00:00
Add new test files to Language directory
This commit is contained in:
1 parent
395657e33c
commit
cb08681a55
28 files changed
+4765
No files matched your search
@@ -0,0 +1,38 @@
|
||||
using Namespace System.Management.Automation.Language
|
||||
Describe "The SafeGetValue method on AST returns safe values" -Tags "DRT" {
|
||||
It "A hashtable is returned from a HashtableAst" {
|
||||
$HashtableAstType = [HashtableAst]
|
||||
$HtAst = {
|
||||
@{ one = 1 }
|
||||
}.ast.Find({$args[0] -is $HashtableAstType}, $true)
|
||||
$HtAst.SafeGetValue().GetType().Name | Should be Hashtable
|
||||
}
|
||||
It "An Array is returned from a LiteralArrayAst" {
|
||||
$ArrayAstType = [ArrayLiteralAst]
|
||||
$ArrayAst = {
|
||||
@( 1,2,3,4)
|
||||
}.ast.Find({$args[0] -is $ArrayAstType}, $true)
|
||||
$ArrayAst.SafeGetValue().GetType().Name | Should be "Object[]"
|
||||
}
|
||||
It "The proper error is returned when a variable is referenced" {
|
||||
$ast = { $a }.Ast.Find({$args[0] -is "VariableExpressionAst"},$true)
|
||||
try {
|
||||
$ast.SafeGetValue() | out-null
|
||||
Throw "Execution Succeeded"
|
||||
}
|
||||
catch {
|
||||
$_.FullyQualifiedErrorId | Should be "InvalidOperationException"
|
||||
$_.ToString() | Should Match '\$a'
|
||||
}
|
||||
}
|
||||
It "A ScriptBlock AST fails with the proper error" {
|
||||
try {
|
||||
{ 1 }.Ast.SafeGetValue()
|
||||
Throw "Execution Succeeded"
|
||||
}
|
||||
catch {
|
||||
$_.FullyQualifiedErrorId | Should be "InvalidOperationException"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
Describe 'Automatic variable $input' {
|
||||
It '$input Type should be enumerator' {
|
||||
function from_begin { [cmdletbinding()]param() begin { Write-Output -NoEnumerate $input } }
|
||||
function from_process { [cmdletbinding()]param() process { Write-Output -NoEnumerate $input } }
|
||||
function from_end { [cmdletbinding()]param() end { Write-Output -NoEnumerate $input } }
|
||||
|
||||
(from_begin) -is [System.Collections.IEnumerator] | Should Be $true
|
||||
(from_process) -is [System.Collections.IEnumerator] | Should Be $true
|
||||
(from_end) -is [System.Collections.IEnumerator] | Should Be $true
|
||||
}
|
||||
|
||||
It 'Empty $input really is empty' {
|
||||
& { @($input).Count } | Should Be 0
|
||||
& { [cmdletbinding()]param() begin { @($input).Count } } | Should Be 0
|
||||
& { [cmdletbinding()]param() process { @($input).Count } } | Should Be 0
|
||||
& { [cmdletbinding()]param() end { @($input).Count } } | Should Be 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
|
||||
$baseTypes = @{
|
||||
[SByte] = 'sbyte'; [Byte] = 'byte'
|
||||
[Int16] = 'short'; [UInt16] = 'ushort'
|
||||
[Int32] = 'int'; [UInt32] = 'uint'
|
||||
[Int64] = 'long'; [UInt64] = 'ulong'
|
||||
}
|
||||
|
||||
$ns = [Guid]::NewGuid() -replace '-',''
|
||||
|
||||
$typeDefinition = "namespace ns_$ns`n{"
|
||||
|
||||
$enumTypeNames = foreach ($baseType in $baseTypes.Keys)
|
||||
{
|
||||
$baseTypeName = $baseTypes[$baseType]
|
||||
$typeDefinition += @"
|
||||
public enum E_$baseTypeName : $baseTypeName
|
||||
{
|
||||
Min = $($baseType::MinValue),
|
||||
MinPlus1 = $($baseType::MinValue + 1),
|
||||
MaxMinus1 = $($baseType::MaxValue - 1),
|
||||
Max = $($baseType::MaxValue)
|
||||
}
|
||||
"@
|
||||
|
||||
"ns_$ns.E_$baseTypeName"
|
||||
}
|
||||
|
||||
$typeDefinition += "`n}"
|
||||
|
||||
Write-Verbose $typeDefinition
|
||||
Add-Type $typeDefinition
|
||||
|
||||
Describe "bnot on enums" -Tags "DRT" {
|
||||
foreach ($enumType in [type[]]$enumTypeNames)
|
||||
{
|
||||
Context $enumType.Name {
|
||||
It "max - 1" {
|
||||
$res = -bnot $enumType::MaxMinus1
|
||||
$res | Should Be $enumType::MinPlus1
|
||||
$res.GetType() | Should Be $enumType
|
||||
}
|
||||
|
||||
It "min + 1" {
|
||||
$res = -bnot $enumType::MinPlus1
|
||||
$res | Should Be $enumType::MaxMinus1
|
||||
$res.GetType() | Should Be $enumType
|
||||
}
|
||||
|
||||
It "Max" {
|
||||
$res = -bnot $enumType::Max
|
||||
$res | Should Be $enumType::Min
|
||||
$res.GetType() | Should Be $enumType
|
||||
}
|
||||
|
||||
It "Min" {
|
||||
$res = -bnot $enumType::Min
|
||||
$res | Should Be $enumType::Max
|
||||
$res.GetType() | Should Be $enumType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "bnot on integral types" -Tags "DRT" {
|
||||
foreach ($baseType in $baseTypes.Keys)
|
||||
{
|
||||
Context $baseType.Name {
|
||||
|
||||
$max = $baseType::MaxValue
|
||||
$maxMinus1 = $max - 1
|
||||
$min = $baseType::MinValue
|
||||
$minPlus1 = $min + 1
|
||||
|
||||
if ([System.Runtime.InteropServices.Marshal]::SizeOf([type]$baseType) -lt 4)
|
||||
{
|
||||
$expectedResultType = [int]
|
||||
}
|
||||
else
|
||||
{
|
||||
$expectedResultType = $baseType
|
||||
}
|
||||
|
||||
if ($baseType -eq [byte] -or $baseType -eq [uint16])
|
||||
{
|
||||
# Because of type promotion rules, unsigned types smaller than int
|
||||
# don't quite follow the pattern of "flip all the bits", so our
|
||||
# tests are a little different.
|
||||
It "max - 1" {
|
||||
$res = -bnot $maxMinus1
|
||||
$res | Should Be (-bnot [int]$maxMinus1)
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "min + 1" {
|
||||
$res = -bnot $minPlus1
|
||||
$res | Should Be (-bnot [int]$minPlus1)
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "max" {
|
||||
$res = -bnot $max
|
||||
$res | Should Be (-bnot [int]$max)
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "min" {
|
||||
$res = -bnot $min
|
||||
$res | Should Be (-bnot [int]$min)
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
It "max - 1" {
|
||||
$res = -bnot $maxMinus1
|
||||
$res | Should Be $minPlus1
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "min + 1" {
|
||||
$res = -bnot $minPlus1
|
||||
$res | Should Be $maxMinus1
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "max" {
|
||||
$res = -bnot $max
|
||||
$res | Should Be $min
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
|
||||
It "min" {
|
||||
$res = -bnot $min
|
||||
$res | Should Be $max
|
||||
$res.GetType() | Should Be $expectedResultType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Describe 'conversion syntax' -Tags "innerloop", "DRT" {
|
||||
# these test suite covers ([<type>]<expression>).<method>() syntax.
|
||||
# it mixes two purposes: casting and super-class method calls.
|
||||
|
||||
It 'converts array of single enum to bool' {
|
||||
# This test relies on the fact that [ConsoleColor]::Black is 0 and all other values are non-zero
|
||||
[bool]@([ConsoleColor]::Black) | Should Be $false
|
||||
[bool]@([ConsoleColor]::Yellow) | Should Be $true
|
||||
}
|
||||
|
||||
It 'calls virtual method non-virtually' {
|
||||
([object]"abc").ToString() | Should Be "System.String"
|
||||
|
||||
# generate random string to avoid JIT optimization
|
||||
$r = [guid]::NewGuid().Guid
|
||||
([object]($r + "a")).Equals(($r + "a")) | Should Be $false
|
||||
}
|
||||
|
||||
It 'calls method on a super-type, when conversion syntax used' {
|
||||
# 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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<#
|
||||
Much of this script belongs in a module, but we don't support importing classes yet.
|
||||
#>
|
||||
using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
using namespace System.Collections
|
||||
using namespace System.Collections.Generic
|
||||
|
||||
#region Testcase infrastructure
|
||||
|
||||
class CompletionTestResult
|
||||
{
|
||||
[string]$CompletionText
|
||||
[string]$ListItemText
|
||||
[CompletionResultType]$ResultType
|
||||
[string]$ToolTip
|
||||
[bool]$Found
|
||||
|
||||
[bool] Equals($Other)
|
||||
{
|
||||
if ($Other -isnot [CompletionTestResult] -and
|
||||
$Other -isnot [CompletionResult])
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
# Comparison is intentionally fuzzy - CompletionText and ResultType must be specified
|
||||
# but the other properties don't need to match if they aren't specified
|
||||
|
||||
if ($this.CompletionText -cne $Other.CompletionText -or
|
||||
$this.ResultType -ne $Other.ResultType)
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
if ($this.ListItemText -cne $Other.ListItemText -and
|
||||
![string]::IsNullOrEmpty($this.ListItemText) -and ![string]::IsNullOrEmpty($Other.ListItemText))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
if ($this.ToolTip -cne $Other.ToolTip -and
|
||||
![string]::IsNullOrEmpty($this.ToolTip) -and ![string]::IsNullOrEmpty($Other.ToolTip))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
class CompletionTestCase
|
||||
{
|
||||
[CompletionTestResult[]]$ExpectedResults
|
||||
[string[]]$NotExpectedResults
|
||||
[string]$TestInput
|
||||
}
|
||||
|
||||
function Get-Completions
|
||||
{
|
||||
param([string]$inputScript, [int]$cursorColumn = $inputScript.Length)
|
||||
|
||||
$results = [System.Management.Automation.CommandCompletion]::CompleteInput(
|
||||
<#inputScript#> $inputScript,
|
||||
<#cursorColumn#> $cursorColumn,
|
||||
<#options#> $null)
|
||||
|
||||
return $results
|
||||
}
|
||||
|
||||
function Get-CompletionTestCaseData
|
||||
{
|
||||
param(
|
||||
[Parameter(ValueFromPipeline)]
|
||||
[hashtable[]]$Data)
|
||||
|
||||
process
|
||||
{
|
||||
Write-Output ([CompletionTestCase[]]$Data)
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Completions
|
||||
{
|
||||
param(
|
||||
[Parameter(ValueFromPipeline)]
|
||||
[CompletionTestCase[]]$TestCases)
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($test in $TestCases)
|
||||
{
|
||||
Context ("Command line: <" + $test.TestInput + ">") {
|
||||
$results = Get-Completions $test.TestInput
|
||||
foreach ($result in $results.CompletionMatches)
|
||||
{
|
||||
foreach ($expected in $test.ExpectedResults)
|
||||
{
|
||||
if ($expected.Equals($result))
|
||||
{
|
||||
$expected.Found = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($expected in $test.ExpectedResults)
|
||||
{
|
||||
It ($expected.CompletionText) {
|
||||
$expected.Found | Should Be $true
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($notExpected in $test.NotExpectedResults)
|
||||
{
|
||||
It "Not expected: $notExpected" {
|
||||
foreach ($result in $results.CompletionMatches)
|
||||
{
|
||||
($result.CompletionText -ceq $notExpected) | Should Be $False
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Testcase infrastructure
|
||||
|
||||
function AlphaArgumentCompleter
|
||||
{
|
||||
param(
|
||||
[string] $CommandName,
|
||||
[string] $parameterName,
|
||||
[string] $wordToComplete,
|
||||
[CommandAst] $commandAst,
|
||||
[IDictionary] $fakeBoundParameters)
|
||||
|
||||
$beta = $fakeBoundParameters['beta']
|
||||
$gamma = $fakeBoundParameters['Gamma']
|
||||
$result = "beta: $beta gamma: $gamma command: $commandName parameterName: $parameterName wordToComplete: $wordToComplete"
|
||||
[CompletionResult]::new($result, $result, "ParameterValue", $result)
|
||||
}
|
||||
|
||||
class BetaArgumentCompleter : IArgumentCompleter
|
||||
{
|
||||
[IEnumerable[CompletionResult]] CompleteArgument(
|
||||
[string] $CommandName,
|
||||
[string] $parameterName,
|
||||
[string] $wordToComplete,
|
||||
[CommandAst] $commandAst,
|
||||
[IDictionary] $fakeBoundParameters)
|
||||
{
|
||||
$resultList = [List[CompletionResult]]::new()
|
||||
|
||||
$alpha = $fakeBoundParameters['Alpha']
|
||||
$gamma = $fakeBoundParameters['Gamma']
|
||||
$result = "alpha: $alpha gamma: $gamma command: $commandName parameterName: $parameterName wordToComplete: $wordToComplete"
|
||||
$resultList.Add([CompletionResult]::new($result, $result, "ParameterValue", $result))
|
||||
|
||||
return $resultList
|
||||
}
|
||||
}
|
||||
|
||||
function TestFunction
|
||||
{
|
||||
param(
|
||||
[ArgumentCompleter({ AlphaArgumentCompleter @args })]
|
||||
$Alpha,
|
||||
[ArgumentCompleter([BetaArgumentCompleter])]
|
||||
$Beta,
|
||||
$Gamma
|
||||
)
|
||||
}
|
||||
|
||||
Describe "Script block based extensible completion" -Tags "Innerloop", "BVT" {
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "beta: 11 gamma: 22 command: TestFunction parameterName: Alpha wordToComplete: aa"
|
||||
ResultType = "ParameterValue"})
|
||||
TestInput = 'TestFunction -Beta 11 -Gamma 22 -Alpha aa'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Test class based extensible completion" -Tags "Innerloop", "BVT" {
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "alpha: 42 gamma: 44 command: TestFunction parameterName: Beta wordToComplete: zz"
|
||||
ResultType = "ParameterValue"})
|
||||
TestInput = 'TestFunction -Alpha 42 -Gamma 44 -Beta zz'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Test registration based exensible completion" -Tags "Innerloop", "BVT" {
|
||||
Register-ArgumentCompleter -Command TestFunction -Parameter Gamma -ScriptBlock {
|
||||
param(
|
||||
[string] $CommandName,
|
||||
[string] $parameterName,
|
||||
[string] $wordToComplete,
|
||||
[CommandAst] $commandAst,
|
||||
[IDictionary] $fakeBoundParameters)
|
||||
|
||||
$beta = $fakeBoundParameters['beta']
|
||||
$alpha = $fakeBoundParameters['alpha']
|
||||
$result = "beta: $beta alpha: $alpha command: $commandName parameterName: $parameterName wordToComplete: $wordToComplete"
|
||||
[CompletionResult]::new($result, $result, "ParameterValue", $result)
|
||||
}
|
||||
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "beta: bb alpha: aa command: TestFunction parameterName: Gamma wordToComplete: 42"
|
||||
ResultType = "ParameterValue"})
|
||||
TestInput = 'TestFunction -Alpha aa -Beta bb -Gamma 42'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Test extensible completion of native commands" -Tags "Innerloop", "BVT" {
|
||||
Register-ArgumentCompleter -Command netsh -Native -ScriptBlock {
|
||||
[CompletionResult]::new('advfirewall', 'advfirewall', "ParameterValue", 'advfirewall')
|
||||
[CompletionResult]::new('bridge', 'bridge', "ParameterValue", 'bridge')
|
||||
}
|
||||
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "advfirewall"; ResultType = "ParameterValue"}
|
||||
@{CompletionText = "bridge"; ResultType = "ParameterValue"}
|
||||
)
|
||||
TestInput = 'netsh '
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Test extensible completion of using namespace" -Tags "Innerloop", "BVT" {
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System"; ResultType = "Namespace"}
|
||||
)
|
||||
TestInput = 'Using namespace sys'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Xml"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Data"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Collections"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.IO"; ResultType = "Namespace"}
|
||||
)
|
||||
TestInput = 'Using namespace system.'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Management.Automation"; ResultType = "Namespace"}
|
||||
)
|
||||
TestInput = 'Using namespace System.Management.Automati'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Management.Automation.Host"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Internal"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Language"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.PerformanceData"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Provider"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Remoting"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Runspaces"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Management.Automation.Security"; ResultType = "Namespace"}
|
||||
)
|
||||
TestInput = 'using namespace System.Management.Automation.'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Type extensible completion of type after using namespace" -Tags "Innerloop", "BVT" {
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "IO.TextReader"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = 'using namespace System; [TextR'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "TextReader"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = 'using namespace System.IO; [TextR'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "Alias"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = '[aliasatt'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "string"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = 'using namespace System; [strin'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
|
||||
Describe "Additional type name completion tests" -Tags "Innerloop", "BVT" {
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System"; ResultType = "Namespace"}
|
||||
@{CompletionText = "System.Security.AccessControl.SystemAcl"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = 'Get-Command -ParameterType System'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Action"; ResultType = "Type"}
|
||||
@{CompletionText = "System.Activator"; ResultType = "Type"}
|
||||
)
|
||||
TestInput = 'Get-Command -ParameterType System.'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Collections.Generic.LinkedList"; ResultType = "Type"; ListItemText = "LinkedList<>"; ToolTip = "Class System.Collections.Generic.LinkedList[T]"}
|
||||
@{CompletionText = "System.Collections.Generic.LinkedListNode"; ResultType = "Type"; ListItemText = "LinkedListNode<>"; ToolTip = "Class System.Collections.Generic.LinkedListNode[T]"}
|
||||
@{CompletionText = "System.Collections.Generic.List"; ResultType = "Type"; ListItemText = "List<>"; ToolTip = "Class System.Collections.Generic.List[T]"}
|
||||
)
|
||||
TestInput = 'Get-Command -ParameterType System.Collections.Generic.Li'
|
||||
},
|
||||
@{
|
||||
ExpectedResults = @(
|
||||
@{CompletionText = "System.Collections.Generic.Dictionary"; ResultType = "Type"; ListItemText = "Dictionary<>"; ToolTip = "Class System.Collections.Generic.Dictionary[TKey, TValue]"}
|
||||
)
|
||||
TestInput = 'Get-Command -ParameterType System.Collections.Generic.Dic'
|
||||
} | Get-CompletionTestCaseData | Test-Completions
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
|
||||
Describe "Clone array" -Tags DRT {
|
||||
It "Cast in target expr" {
|
||||
(([int[]](42)).clone()) | Should Be 42
|
||||
(([int[]](1..5)).clone()).Length | Should Be 5
|
||||
(([int[]](1..5)).clone()).GetType() | Should Be ([int[]])
|
||||
|
||||
}
|
||||
It "Cast not in target expr" {
|
||||
$e = [int[]](42)
|
||||
$e.Clone() | Should Be 42
|
||||
$e = [int[]](1..5)
|
||||
$e.Clone().Length | Should Be 5
|
||||
$e.Clone().GetType() | Should Be ([int[]])
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Set fields through PSMemberInfo" -Tags DRT {
|
||||
Add-Type @"
|
||||
public struct AStruct { public string s; }
|
||||
"@
|
||||
|
||||
It "via cast" {
|
||||
([AStruct]@{s = "abc" }).s | Should Be "abc"
|
||||
}
|
||||
It "via new-object" {
|
||||
(new-object AStruct -prop @{s="abc"}).s | Should Be "abc"
|
||||
}
|
||||
It "via PSObject" {
|
||||
$x = [AStruct]::new()
|
||||
$x.psobject.properties['s'].Value = 'abc'
|
||||
$x.s | Should Be "abc"
|
||||
}
|
||||
}
|
||||
|
||||
Describe "MSFT:3309783" -Tags DRT {
|
||||
|
||||
It "Run in another process" {
|
||||
# For a reliable test, we must run this in a new process because an earlier binding in this process
|
||||
# could mask the bug/fix.
|
||||
powershell -noprofile -command "[psobject] | % FullName" | Should Be System.Management.Automation.PSObject
|
||||
}
|
||||
|
||||
It "Run in current process" {
|
||||
# For good measure, do the same thing in this process
|
||||
[psobject] | % FullName | Should Be System.Management.Automation.PSObject
|
||||
}
|
||||
|
||||
It "Pipe objects derived from PSObject" {
|
||||
# Related - make sure we can still pipe objects derived from PSObject
|
||||
class MyPsObj : PSObject
|
||||
{
|
||||
MyPsObj($obj) : base($obj) { }
|
||||
[string] ToString() {
|
||||
# Don't change access via .psobject, that was also a bug.
|
||||
return "MyObj: " + $this.psobject.BaseObject
|
||||
}
|
||||
}
|
||||
|
||||
[MyPsObj]::new("abc").psobject.ToString() | Should Be "MyObj: abc"
|
||||
[MyPsObj]::new("def") | Out-String | % Trim | Should Be "MyObj: def"
|
||||
}
|
||||
}
|
||||
|
||||
Describe "ScriptBlockAst.GetScriptBlock throws on error" -Tags DRT {
|
||||
|
||||
$e = $null
|
||||
|
||||
It "with parse error" {
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput('function ', [ref]$null, [ref]$e)
|
||||
{ $ast.GetScriptBlock() } | Should Throw
|
||||
}
|
||||
|
||||
|
||||
It "with semantic errors" {
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput('function foo{param()begin{}end{[ref][ref]1}dynamicparam{}}', [ref]$null, [ref]$e)
|
||||
|
||||
{ $ast.GetScriptBlock() } | Should Throw
|
||||
{ $ast.EndBlock.Statements[0].Body.GetScriptBlock() } | Should Throw
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Hashtable key property syntax" -Tags DRT {
|
||||
$script = @'
|
||||
# First create a hashtable wrapped in PSObject
|
||||
$hash = New-Object hashtable
|
||||
$key = [ConsoleColor]::Red
|
||||
$null = $hash.$key
|
||||
$hash = @{}
|
||||
$hash.$key = 'Hello'
|
||||
# works in PS 2,3,4. Fails in PS 5:
|
||||
$hash.$key
|
||||
'@
|
||||
|
||||
It "In current process" {
|
||||
# Run in current process, but something that ran earlier could influence
|
||||
# the result
|
||||
Invoke-Expression $script | Should Be Hello
|
||||
}
|
||||
|
||||
It "In different process" {
|
||||
# So also run in a fresh process
|
||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($script)
|
||||
powershell -noprofile -encodedCommand ([Convert]::ToBase64String($bytes)) | Should Be Hello
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Assign automatic variables" -Tags DRT {
|
||||
|
||||
$autos = '_', 'args', 'this', 'input', 'pscmdlet', 'psboundparameters', 'myinvocation', 'psscriptroot', 'pscommandpath'
|
||||
|
||||
foreach ($auto in $autos)
|
||||
{
|
||||
It "Assign auto w/ invalid type constraint - $auto" {
|
||||
{ & ([ScriptBlock]::Create("[datetime]`$$auto = 1")) } | Should Throw $auto
|
||||
{ . ([ScriptBlock]::Create("[datetime]`$$auto = 1")) } | Should Throw $auto
|
||||
{ & ([ScriptBlock]::Create("[runspace]`$$auto = 1")) } | Should Throw $auto
|
||||
{ . ([ScriptBlock]::Create("[runspace]`$$auto = 1")) } | Should Throw $auto
|
||||
{ & ([ScriptBlock]::Create("[notexist]`$$auto = 1")) } | Should Throw $auto
|
||||
{ . ([ScriptBlock]::Create("[notexist]`$$auto = 1")) } | Should Throw $auto
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($auto in $autos)
|
||||
{
|
||||
It "Assign auto w/o type constraint - $auto" {
|
||||
& ([ScriptBlock]::Create("`$$auto = 1; `$$auto")) | Should Be 1
|
||||
. ([ScriptBlock]::Create("`$$auto = 1; `$$auto")) | Should Be 1
|
||||
}
|
||||
}
|
||||
|
||||
It "Assign auto w/ correct type constraint" {
|
||||
& { [object]$_ = 1; $_ } | Should Be 1
|
||||
& { [object[]]$args = 1; $args } | Should Be 1
|
||||
& { [object]$this = 1; $this } | Should Be 1
|
||||
& { [object]$input = 1; $input } | Should Be 1
|
||||
# Can't test PSCmdlet or PSBoundParameters, they use an internal type
|
||||
& { [System.Management.Automation.InvocationInfo]$myInvocation = $myInvocation; $myInvocation.Line } | Should Match Automation.InvocationInfo
|
||||
& { [string]$PSScriptRoot = 'abc'; $PSScriptRoot } | Should Be abc
|
||||
& { [string]$PSCommandPath = 'abc'; $PSCommandPath } | Should Be abc
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Attribute error position" -Tags DRT {
|
||||
It "Ambiguous overloads" {
|
||||
try
|
||||
{
|
||||
& {
|
||||
param(
|
||||
[ValidateNotNull(1,2,3,4)]
|
||||
$param
|
||||
)
|
||||
}
|
||||
throw "Should have thrown"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.InvocationInfo.Line | Should Match ValidateNotNull
|
||||
$_.FullyQualifiedErrorId | Should Be MethodCountCouldNotFindBest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Multiple alias attributes" -Tags DRT {
|
||||
It "basic test" {
|
||||
function foo {
|
||||
param(
|
||||
[alias('aa')]
|
||||
[alias('bb')]
|
||||
$cc
|
||||
)
|
||||
$cc
|
||||
}
|
||||
|
||||
foo -aa 1 | Should Be 1
|
||||
foo -bb 2 | Should Be 2
|
||||
foo -cc 3 | Should Be 3
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Members of System.Type" -Tags DRT {
|
||||
It "Members in public classes derived from System.Type should be found" {
|
||||
class MyType : System.Collections.IEnumerable
|
||||
{
|
||||
[System.Collections.IEnumerator] GetEnumerator() { return $null }
|
||||
}
|
||||
|
||||
[type] | Get-Member ImplementedInterfaces | Should Be 'System.Collections.Generic.IEnumerable[type] ImplementedInterfaces {get;}'
|
||||
[MyType].ImplementedInterfaces | Should Be System.Collections.IEnumerable
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
Describe "Interface inheritance with remoting proxies" -Tags "P1", "RI" {
|
||||
$src = @"
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
|
||||
namespace MSFT_716893
|
||||
{
|
||||
[ServiceContract]
|
||||
public interface IInterface1
|
||||
{
|
||||
[OperationContract]string BaseOperation(int i);
|
||||
}
|
||||
|
||||
[ServiceContract]
|
||||
public interface IInterface2 : IInterface1
|
||||
{
|
||||
[OperationContract(Name="op1")]string Operation(string a);
|
||||
[OperationContract(Name="op2")]string Operation(string a, string b);
|
||||
}
|
||||
|
||||
public class ServiceImplementation : IInterface2
|
||||
{
|
||||
public string Operation(string a) { return "1 - " + a; }
|
||||
public string Operation(string a, string b) { return "2 - " + a + " " + b; }
|
||||
public string BaseOperation(int i) { return "3 - " + i; }
|
||||
}
|
||||
|
||||
public static class Service
|
||||
{
|
||||
static ServiceHost serviceHost;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Uri baseAddress = new Uri("http://localhost:8080/service");
|
||||
serviceHost = new ServiceHost(typeof(ServiceImplementation), baseAddress);
|
||||
serviceHost.Open();
|
||||
}
|
||||
|
||||
public static IInterface1 GetProxy()
|
||||
{
|
||||
ChannelFactory<IInterface2> factory = new ChannelFactory<IInterface2>(
|
||||
serviceHost.Description.Endpoints[0].Binding,
|
||||
serviceHost.Description.Endpoints[0].Address);
|
||||
return factory.CreateChannel();
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
serviceHost.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
Add-Type -TypeDefinition $src -ReferencedAssemblies System.ServiceModel.dll
|
||||
|
||||
BeforeEach {
|
||||
[MSFT_716893.Service]::Init()
|
||||
$proxy = [MSFT_716893.Service]::GetProxy()
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
[MSFT_716893.Service]::Close()
|
||||
}
|
||||
|
||||
It "Direct invocation" {
|
||||
$proxy.Operation("a") | Should Be "1 - a"
|
||||
$proxy.Operation("a", "b") | Should Be "2 - a b"
|
||||
$proxy.BaseOperation(42) | Should Be "3 - 42"
|
||||
}
|
||||
|
||||
It "Invocation via method constraints" {
|
||||
([MSFT_716893.IInterface2]$proxy).Operation("c") | Should Be "1 - c"
|
||||
([MSFT_716893.IInterface2]$proxy).Operation("d", "e") | Should Be "2 - d e"
|
||||
([MSFT_716893.IInterface1]$proxy).BaseOperation(22) | Should Be "3 - 22"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
Describe 'Argument transformation attribute on optional argument with explicit $null' -Tags "P1", "RI" {
|
||||
$mod = Add-Type -PassThru -TypeDefinition @'
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MSFT_1407291
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
|
||||
public class AddressTransformationAttribute : ArgumentTransformationAttribute
|
||||
{
|
||||
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData)
|
||||
{
|
||||
return (ulong) 42;
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "CSharpCmdletTakesUInt64")]
|
||||
[OutputType(typeof(System.String))]
|
||||
public class Cmdlet1 : PSCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = false)]
|
||||
[AddressTransformation]
|
||||
public ulong Address { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
WriteObject(Address);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "CSharpCmdletTakesObject")]
|
||||
[OutputType(typeof(System.String))]
|
||||
public class Cmdlet2 : PSCmdlet
|
||||
{
|
||||
[Parameter(Mandatory = false)]
|
||||
[AddressTransformation]
|
||||
public object Address { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
WriteObject(Address ?? "passed in null");
|
||||
}
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
Import-Module $mod[0].Assembly
|
||||
|
||||
function Invoke-ScriptFunctionTakesObject
|
||||
{
|
||||
param([MSFT_1407291.AddressTransformation()]
|
||||
[Parameter(Mandatory = $false)]
|
||||
[object]$Address = "passed in null")
|
||||
|
||||
return $Address
|
||||
}
|
||||
|
||||
function Invoke-ScriptFunctionTakesUInt64
|
||||
{
|
||||
param([MSFT_1407291.AddressTransformation()]
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Uint64]$Address = 11)
|
||||
|
||||
return $Address
|
||||
}
|
||||
|
||||
|
||||
Invoke-ScriptFunctionTakesObject | Should Be 42
|
||||
Invoke-ScriptFunctionTakesUInt64 | Should Be 42
|
||||
Invoke-CSharpCmdletTakesObject | Should Be "passed in null"
|
||||
Invoke-CSharpCmdletTakesUInt64 | Should Be 0
|
||||
|
||||
Invoke-ScriptFunctionTakesObject -Address $null | Should Be 42
|
||||
Invoke-ScriptFunctionTakesUInt64 -Address $null | Should Be 42
|
||||
Invoke-CSharpCmdletTakesObject -Address $null | Should Be 42
|
||||
Invoke-CSharpCmdletTakesUInt64 -Address $null | Should Be 42
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
Describe "Redirection operator now supports encoding changes" {
|
||||
BeforeAll {
|
||||
$asciiString = "abc"
|
||||
$asciiCR = "`r`n"
|
||||
|
||||
# If out-file -encoding happens to have a default, be sure to
|
||||
# save it away
|
||||
$SavedValue = $null
|
||||
$oldDefaultParameterValues = $psDefaultParameterValues
|
||||
$psDefaultParameterValues = @{}
|
||||
}
|
||||
AfterAll {
|
||||
# be sure to tidy up afterwards
|
||||
$psDefaultParameterValues = $oldDefaultParameterValues
|
||||
}
|
||||
BeforeEach {
|
||||
# start each test with a clean plate!
|
||||
$psdefaultParameterValues.Remove("out-file:encoding")
|
||||
}
|
||||
AfterEach {
|
||||
# end each test with a clean plate!
|
||||
$psdefaultParameterValues.Remove("out-file:encoding")
|
||||
}
|
||||
|
||||
It "If encoding is unset, redirection should be Unicode" {
|
||||
$asciiString > TESTDRIVE:\file.txt
|
||||
$bytes = get-content -encoding byte TESTDRIVE:\file.txt
|
||||
# create the expected
|
||||
$BOM = [text.encoding]::unicode.GetPreamble()
|
||||
$TXT = [text.encoding]::unicode.GetBytes($asciiString)
|
||||
$CR = [text.encoding]::unicode.GetBytes($asciiCR)
|
||||
$expectedBytes = .{ $BOM; $TXT; $CR }
|
||||
$bytes.Count | should be $expectedBytes.count
|
||||
for($i = 0; $i -lt $bytes.count; $i++) {
|
||||
$bytes[$i] | Should be $expectedBytes[$i]
|
||||
}
|
||||
}
|
||||
|
||||
# $availableEncodings = "unknown","string","unicode","bigendianunicode","utf8","utf7", "utf32","ascii","default","oem"
|
||||
$availableEncodings = (get-command out-file).Parameters["Encoding"].Attributes.ValidValues
|
||||
|
||||
foreach($encoding in $availableEncodings) {
|
||||
# some of the encodings accepted by out-file aren't real,
|
||||
# and out-file has its own translation, so we'll
|
||||
# not do that logic here, but simply ignore those encodings
|
||||
# as they eventually are translated to "real" encoding
|
||||
$enc = [system.text.encoding]::$encoding
|
||||
if ( $enc )
|
||||
{
|
||||
$msg = "Overriding encoding for out-file is respected for $encoding"
|
||||
$BOM = $enc.GetPreamble()
|
||||
$TXT = $enc.GetBytes($asciiString)
|
||||
$CR = $enc.GetBytes($asciiCR)
|
||||
$expectedBytes = .{ $BOM; $TXT; $CR }
|
||||
$psdefaultparameterValues["out-file:encoding"] = "$encoding"
|
||||
$asciiString > TESTDRIVE:/file.txt
|
||||
$observedBytes = Get-Content -encoding Byte TESTDRIVE:/file.txt
|
||||
# THE TEST
|
||||
It $msg {
|
||||
$observedBytes.Count | Should be $expectedBytes.Count
|
||||
for($i = 0;$i -lt $observedBytes.Count; $i++) {
|
||||
$observedBytes[$i] | Should be $expectedBytes[$i]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
Describe "Type accelerators" -Tags "DRT" {
|
||||
$TypeAcceleratorsType = [psobject].Assembly.GetType("System.Management.Automation.TypeAccelerators")
|
||||
|
||||
$TypeAccelerators = $TypeAcceleratorsType::Get
|
||||
$TypeAcceleratorsType::Add('msft_2174855', [int])
|
||||
$TypeAcceleratorsType::Add('msft_2174855_rm', [int])
|
||||
|
||||
It "Basic type accelerator usage" {
|
||||
[msft_2174855] | Should Be ([int])
|
||||
}
|
||||
|
||||
It "Can query type accelerators" {
|
||||
$TypeAccelerators.Count -gt 82 | Should Be $true
|
||||
$TypeAccelerators['xml'] | Should Be ([System.Xml.XmlDocument])
|
||||
$TypeAccelerators['AllowNull'] | Should Be ([System.Management.Automation.AllowNullAttribute])
|
||||
}
|
||||
|
||||
It "Can remove type accelerator" {
|
||||
$TypeAcceleratorsType::Get['msft_2174855_rm'] | Should Be ([int])
|
||||
$TypeAcceleratorsType::Remove('msft_2174855_rm')
|
||||
$TypeAcceleratorsType::Get['msft_2174855_rm'] | Should Be $null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
Describe "Using assembly" -Tags "DRT" {
|
||||
|
||||
try
|
||||
{
|
||||
pushd $PSScriptRoot
|
||||
$guid = [Guid]::NewGuid()
|
||||
|
||||
Add-Type -OutputAssembly $PSScriptRoot\UsingAssemblyTest$guid.dll -TypeDefinition @"
|
||||
public class ABC {}
|
||||
"@
|
||||
|
||||
It 'parse reports error on non-existing assembly by relative path' {
|
||||
$err = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly foo.dll", [ref]$null, [ref]$err)
|
||||
|
||||
$err.Count | Should Be 1
|
||||
$err[0].ErrorId | Should Be ErrorLoadingAssembly
|
||||
}
|
||||
|
||||
It 'parse reports error on assembly with non-existing fully qualified name' {
|
||||
$err = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly 'System.Management.Automation, Version=99.0.0.0'", [ref]$null, [ref]$err)
|
||||
|
||||
$err.Count | Should Be 1
|
||||
$err[0].ErrorId | Should Be ErrorLoadingAssembly
|
||||
}
|
||||
|
||||
It 'not allow UNC path' {
|
||||
$err = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly \\networkshare\foo.dll", [ref]$null, [ref]$err)
|
||||
|
||||
$err.Count | Should Be 1
|
||||
$err[0].ErrorId | Should Be CannotLoadAssemblyFromUncPath
|
||||
}
|
||||
|
||||
It 'not allow http path' {
|
||||
$err = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly http://microsoft.com/foo.dll", [ref]$null, [ref]$err)
|
||||
|
||||
$err.Count | Should Be 1
|
||||
$err[0].ErrorId | Should Be CannotLoadAssemblyWithUriSchema
|
||||
}
|
||||
|
||||
It "parse does not load the assembly" {
|
||||
$assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $false
|
||||
|
||||
$err = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly .\UsingAssemblyTest$guid.dll", [ref]$null, [ref]$err)
|
||||
|
||||
$assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $false
|
||||
$err.Count | Should Be 0
|
||||
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly '$PSScriptRoot\UsingAssemblyTest$guid.dll'", [ref]$null, [ref]$err)
|
||||
|
||||
$assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $false
|
||||
$err.Count | Should Be 0
|
||||
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly `"$PSScriptRoot\UsingAssemblyTest$guid.dll`"", [ref]$null, [ref]$err)
|
||||
|
||||
$assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $false
|
||||
$err.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "reports runtime error about non-existing assembly with relative path" {
|
||||
$failed = $true
|
||||
try {
|
||||
[scriptblock]::Create("using assembly .\NonExistingAssembly.dll")
|
||||
$failed = $false
|
||||
} catch {
|
||||
$_.FullyQualifiedErrorId | Should be 'ParseException'
|
||||
$_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should be 'ErrorLoadingAssembly'
|
||||
}
|
||||
$failed | Should be $true
|
||||
}
|
||||
#>
|
||||
It "Assembly loaded at runtime" {
|
||||
$assemblies = powershell -noprofile -command @"
|
||||
using assembly .\UsingAssemblyTest$guid.dll
|
||||
[Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
"@
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $true
|
||||
|
||||
$assemblies = powershell -noprofile -command @"
|
||||
using assembly $PSScriptRoot\UsingAssemblyTest$guid.dll
|
||||
[Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
"@
|
||||
$assemblies -contains "UsingAssemblyTest$guid" | Should Be $true
|
||||
|
||||
|
||||
$assemblies = powershell -noprofile -command @"
|
||||
using assembly System.Drawing
|
||||
[Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
"@
|
||||
$assemblies -contains "System.Drawing" | Should Be $true
|
||||
|
||||
$assemblies = powershell -noprofile -command @"
|
||||
using assembly 'System.Drawing, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
|
||||
[Appdomain]::CurrentDomain.GetAssemblies().GetName().Name
|
||||
"@
|
||||
$assemblies -contains "System.Drawing" | Should Be $true
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Remove-Item .\UsingAssemblyTest$guid.dll
|
||||
popd
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
# There is an automatic 'using namespace system' which is
|
||||
# tested by this test, so don't uncomment the following:
|
||||
#using namespace System
|
||||
using namespace System.Threading
|
||||
using namespace System.Timers
|
||||
# Test parsing more than one using statement on one line
|
||||
using namespace System.Diagnostics; using namespace System.Runtime.CompilerServices
|
||||
using namespace System.Collections.Generic
|
||||
|
||||
Import-Module $PSScriptRoot\..\LanguageTestSupport.psm1
|
||||
|
||||
function ShouldBeErrorId
|
||||
{
|
||||
param([Parameter(ValueFromPipeline, Mandatory)]
|
||||
[ScriptBlock]
|
||||
$sb,
|
||||
|
||||
[Parameter(Mandatory, Position=0)]
|
||||
[string]
|
||||
$FullyQualifiedErrorId)
|
||||
|
||||
try
|
||||
{
|
||||
& $sb
|
||||
throw "Unexpected"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.FullyQualifiedErrorId | Should Be $FullyQualifiedErrorId
|
||||
}
|
||||
}
|
||||
|
||||
# Flags is System.FlagsAttribute
|
||||
# This tests our implicit 'using namespace System'
|
||||
# despite having other explicit using namespace statements.
|
||||
[Flags()]
|
||||
enum E1
|
||||
{
|
||||
E1 = 0x01
|
||||
E2 = 0x02
|
||||
E4 = 0x04
|
||||
}
|
||||
|
||||
# Test attributes that won't be found w/o using, but w/o implicit Attribute suffix
|
||||
[CompilerGenerated()]
|
||||
class C1
|
||||
{
|
||||
[Thread][CompilerGenerated()]$Thread
|
||||
[Int32][CompilerGenerated()]$Int
|
||||
[ElapsedEventHandler][CompilerGenerated()]$EventHandler
|
||||
}
|
||||
|
||||
# Test attributes that won't be found w/o using, but w/ implicit Attribute suffix
|
||||
[CompilerGeneratedAttribute()]
|
||||
class C2
|
||||
{
|
||||
[Thread][CompilerGeneratedAttribute()]$Thread
|
||||
[Int32][CompilerGeneratedAttribute()]$Int
|
||||
[ElapsedEventHandler][CompilerGeneratedAttribute()]$EventHandler
|
||||
}
|
||||
|
||||
Describe "Using Namespace" -Tags "DRT" {
|
||||
It "Type literals w/ using namespace" {
|
||||
[Thread].FullName | Should Be System.Threading.Thread
|
||||
[Int32].FullName | Should Be System.Int32
|
||||
[ElapsedEventHandler].FullName | Should Be System.Timers.ElapsedEventHandler
|
||||
|
||||
[C1].GetProperty("Thread").PropertyType.FullName | Should Be System.Threading.Thread
|
||||
[C1].GetProperty("Int").PropertyType.FullName | Should Be System.Int32
|
||||
[C1].GetProperty("EventHandler").PropertyType.FullName | Should Be System.Timers.ElapsedEventHandler
|
||||
}
|
||||
|
||||
It "Covert string to Type w/ using namespace" {
|
||||
("Thread" -as [Type]).FullName | Should Be System.Threading.Thread
|
||||
("Int32" -as [Type]).FullName | Should Be System.Int32
|
||||
("ElapsedEventHandler" -as [Type]).FullName | Should Be System.Timers.ElapsedEventHandler
|
||||
|
||||
New-Object Int32 | Should Be 0
|
||||
New-Object CompilerGeneratedAttribute | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
}
|
||||
|
||||
It "Attributes w/ using namespace" {
|
||||
function foo
|
||||
{
|
||||
[DebuggerStepThrough()]
|
||||
param(
|
||||
[CompilerGeneratedAttribute()]
|
||||
$a,
|
||||
|
||||
[CompilerGenerated()]
|
||||
$b
|
||||
)
|
||||
|
||||
"OK"
|
||||
}
|
||||
|
||||
foo | Should Be OK
|
||||
$cmdInfo = gcm foo
|
||||
$cmdInfo.ScriptBlock.Attributes[0] | Should Be System.Diagnostics.DebuggerStepThroughAttribute
|
||||
$cmdInfo.Parameters['a'].Attributes[1] | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
$cmdInfo.Parameters['b'].Attributes[1] | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
|
||||
[C1].GetProperty("Thread").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
[C1].GetProperty("Int").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
[C1].GetProperty("EventHandler").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
|
||||
[C2].GetProperty("Thread").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
[C2].GetProperty("Int").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
[C2].GetProperty("EventHandler").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
|
||||
[C1].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
[C2].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute
|
||||
|
||||
[E1].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.FlagsAttribute
|
||||
}
|
||||
|
||||
It "Ambiguous type reference" {
|
||||
{ [Timer] } | ShouldBeErrorId AmbiguousTypeReference
|
||||
}
|
||||
|
||||
It "Parameters" {
|
||||
function foo([Thread]$t = $null) { 42 }
|
||||
|
||||
foo | Should Be 42
|
||||
|
||||
$mod = New-Module -Name UsingNamespaceModule -ScriptBlock {
|
||||
function Set-Thread([Thread]$t = $null)
|
||||
{
|
||||
44
|
||||
}
|
||||
}
|
||||
Import-Module $mod
|
||||
Set-Thread | Should Be 44
|
||||
Remove-Module $mod
|
||||
}
|
||||
|
||||
It "Generics" {
|
||||
function foo([List[string]]$l)
|
||||
{
|
||||
$l | Should Be "a string"
|
||||
}
|
||||
|
||||
$l = [List[string]]::new()
|
||||
$l.Add("a string")
|
||||
foo $l
|
||||
}
|
||||
|
||||
ShouldBeParseError "1; using namespace System" UsingMustBeAtStartOfScript 3
|
||||
ShouldBeParseError "using namespace Foo = System" UsingStatementNotSupported 0
|
||||
# TODO: add diagnostic (low pri)
|
||||
# ShouldBeParseError "using namespace System; using namespace System" UsingNamespaceAlreadySpecified 24
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user