-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathClipboardText.Tests.ps1
200 lines (176 loc) · 9.18 KB
/
ClipboardText.Tests.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<# Note:
* Make sure this file is saved as *UT8 with BOM*, so that
literal non-ASCII characters are interpreted correctly.
* When run in WinPSv3+, an attempt is made to run the tests in WinPSv2
too, but note that requires prior installation of v2 support.
Also, in PSv2, Pester must be loaded *manually*, via the *full
path to its *.psd1 file* (seemingly, v2 doesn't find modules located in
\<version>\ subdirs.).
For interactive use, the simplest approach is to invoke v2 as follows:
powershell.exe -version 2 -Command "Import-Module '$((Get-Module Pester).Path)'
#>
# Abort on all unhandled errors.
$ErrorActionPreference = 'Stop'
# PSv2 compatibility: makes sure that $PSScriptRoot reflects this script's folder.
if (-not $PSScriptRoot) { $PSScriptRoot = $MyInvocation.MyCommand.Path }
# Turn on the latest strict mode, so as to make sure that the ScriptsToProcess
# script that runs the prerequisites-check script dot-sourced also works
# properly when the caller happens to run with Set-StrictMode -Version Latest
# in effect.
Set-StrictMode -Version Latest
# Force-(re)import this module.
# Target the *.psd1 file explicitly, so the tests can run from versioned subfolders too. Note that the
# loaded module's ModuleInfo's .Path property will reflect the *.psm1 instead.
$manifest = (Get-Item $PSScriptRoot/*.psd1)
Remove-Module -ea Ignore -Force $manifest.BaseName # Note: To be safe, we unload any modules with the same name first (they could be in a different location and end up side by side in memory with this one.)
# !! In PSv2, this statement causes Pester to run all tests TWICE (?!)
Import-Module $manifest -Force -Global # -Global makes sure that when psake runs tester in a child scope, the module is still imported globally.
# Use the platform-appropiate newline.
$nl = [Environment]::NewLine
# See if we're running on *Windows PowerShell*
$isWinPs = $null, 'Desktop' -contains $PSVersionTable.PSEdition
Describe StringInputTest {
It "Copies and pastes a string correctly." {
$string = "Here at $(Get-Date)"
Set-ClipboardText $string
Get-ClipboardText | Should -BeExactly $string
}
It "Correctly round-trips non-ASCII characters." {
$string = 'Thomas Hübl''s talk about 中文'
$string | Set-ClipboardText
Get-ClipboardText | Should -BeExactly $string
}
It "Outputs an array of lines by default" {
$lines = 'one', 'two'
$string = $lines -join [Environment]::NewLine
Set-ClipboardText $string
Get-ClipboardText | Should -BeExactly $lines
}
It "Retrieves a multi-line string as-is with -Raw and doesn't append an extra newline." {
"2 lines${nl}with 1 trailing newline${nl}" | Set-ClipboardText
Get-ClipboardText -Raw | Should -Not -Match '(\r?\n){2}\z'
}
}
Describe EmptyTests {
BeforeEach {
'dummy' | Set-ClipboardText # make sure we start with a nonempty clipboard so we can verify that clearing is effective
}
It "Not providing input effectively clears the clipboard." {
Set-ClipboardText # no input
$null -eq (Get-ClipboardText -Raw) | Should -BeTrue
}
It "Passing the empty string effectively clears the clipboard." {
Set-ClipboardText -InputObject '' # Note The PsWinV5+ Set-Clipboard reports a spurious error with '', which we mask behind the scenes.
$null -eq (Get-ClipboardText -Raw) | Should -BeTrue
}
It "Passing `$null effectively clears the clipboard." {
Set-ClipboardText -InputObject $null
$null -eq (Get-ClipboardText -Raw) | Should -BeTrue
}
}
Describe PassThruTest {
It "Set-ClipboardText -PassThru also outputs the text." {
$in = "line 1${nl}line 2"
$out = $in | Set-ClipboardText -PassThru
Get-ClipboardText -Raw | Should -BeExactly $in
$out | Should -BeExactly $in
}
}
Describe CommandInputTest {
It "Copies and pastes a PowerShell command's output correctly" {
Get-Item / | Set-ClipboardText
# Note: Inside Set-ClipboardText we remove the trailing newline that
# Out-String invariably adds, so we must do the same here.
$shouldBe = (Get-Item / | Out-String) -replace '\r?\n\z'
$pasted = Get-ClipboardText -Raw
$pasted | Should -BeExactly $shouldBe
}
It "Copies and pastes an external program's output correctly" {
# Note: whoami without argument works on all supported platforms.
whoami | Set-ClipboardText
$shouldBe = whoami
$is = Get-ClipboardText
$is | Should -Be $shouldBe
}
}
Describe OutputWidthTest {
BeforeAll {
# A custom object that is implicitly formatted with Format-Table with
# 2 columns.
$obj = [pscustomobject] @{ one = '1' * 40; two = '2' * 216 }
}
It "Truncates lines that are too wide for the specified width" {
$obj | Set-ClipboardText -Width 80
# Note: [3] - the *4th* line - is the line with the two column values in all editions.
# [-2] to use the penultimate line is NOT reliable, as the editions differ in
# the number of trailing newlines.
(Get-ClipboardText)[3] | Should -Match '(\.\.\.|…)$' # Note: At some point, PS Core started using the '…' (horizontal ellipsis) Unicode char. instead of three periods.
}
It "Allows incrementing the width to accommodate wider lines" {
$obj | Set-ClipboardText -Width 257 # 40 + 1 (space between columns) + 216
(Get-ClipboardText)[3].TrimEnd() | Should -BeLikeExactly '*2'
}
}
# Note: These tests apply to PS *Core* only, because Windows PowerShell doesn't require external utilities for clipboard support.
Describe MissingExternalUtilityTest {
# We skip these tests in *Windows PowerShell*, because Windows Powershell
# does't require external utilities for access to the clipboard.
# Note: We don't exit right away, because do want to invoke the `It` block
# with `-Skip` set to $True, so that the results indicated that the test
# was deliberately skipped.
if (-not $isWinPs) {
# Determine the name of the module being tested.
# For a Mock to be effective in the target module's context, it must be
# defined with -ModuleName <name>.
$thisModuleName = (Split-Path -Leaf $PSScriptRoot)
# Define the platform-appropiate mocks for calling the external clipboard
# utilities.
# Note: Since mocking by full executable path isn't supported, we use
# helper function invoke-External.
# ??? TODO: These tests no longer work in Pester 5.x
# macOS, Linux:
Mock invoke-External -ParameterFilter { $LiteralPath -eq '/bin/sh' } {
/bin/sh -c 'nosuchexe'
} -ModuleName $thisModuleName
# Windows:
Mock invoke-External -ParameterFilter { $LiteralPath -eq "$env:SystemRoot\System32\cmd.exe" } {
& "$env:SystemRoot\System32\cmd.exe" /c 'nosuchexe'
} -ModuleName $thisModuleName
}
It "PS Core: Generates a statement-terminating error when the required external utility is not present" -Skip:$isWinPs {
{ 'dummy' | Set-ClipboardText 2>$null } | Should -Throw
}
}
Describe MTAtests {
# Windows PowerShell:
# A WinForms text-box workaround is needed when PowerShell is running in COM MTA
# (multi-threaded apartment) mode.
# By default, v2 runs in MTA mode and v3+ in STA mode.
# However, you can *opt into* MTA mode in v3+, and the workaround is then needed too.
# (In PSCore on Windows, MTA is the default again, but it has no access to WinForms
# anyway and uses external utility clip.exe instead.)
It "Windows PowerShell: Works in MTA mode" -Skip:(-not $isWinPs -or $PSVersionTable.PSVersion.Major -eq 2) {
# Recursively invokes the 'StringInputTest' tests.
# !! This produces NO OUTPUT; to troubleshoot, run the command interactively from the project folder.
# !! As of Windows PowerShell v5.1.18362.145 on Microsoft Windows 10 Pro (64-bit; Version 1903, OS Build: 18362.175),
# !! `Get-Command -Name Add-Member, Get-ChildItem` must be executed BEFORE invoking Pester; without it,
# !! Pester inexplicably fails to locate these commands during module import and cannot be loaded.
powershell.exe -noprofile -MTA -Command "if ([threading.thread]::CurrentThread.ApartmentState.ToString() -ne 'MTA') { Throw "Not in MTA mode." }; Get-Command -Name Add-Member, Get-ChildItem; Invoke-Pester -Name StringInputTest -EnableExit"
$LASTEXITCODE | Should -Be 0
}
}
Describe v2Tests {
# Invoke these tests in *WinPS v2*, which amounts to a RECURSION.
# Therefore, EXECUTION TAKES A WHILE.
It "Windows PowerShell: Passes all tests in v2 as well." -Skip:(-not $isWinPs -or $PSVersionTable.PSVersion.Major -eq 2) {
# !! An Install-Module-installed Pester is located in a version-named subfolder, which v2 cannot
# !! detect, so we import Pester by explicit path.
# !! Also `-version 2` must be the *first* argument passed to `powershell.exe`.
#
# !! NO OUTPUT IS PRODUCED - to troubleshoot, run the command interactively from the project folder.
# !! Notably, *prior installation of v2 support is needed*, and PowerShell seems to quietly ignore `-version 2`
# !! in its absence, so we have to test from *within* the session.
powershell.exe -version 2 -noprofile -Command "Set-StrictMode -Version Latest; Import-Module '$((Get-Module Pester).Path)'; if (`$PSVersionTable.PSVersion.Major -ne 2) { Throw 'v2 SUPPORT IS NOT INSTALLED.' }; Invoke-Pester"
$LASTEXITCODE | Should -Be 0
}
}