2020-03-24 11:08:37 -07:00
# Copyright (c) Microsoft Corporation.
2018-02-13 09:23:53 -08:00
# Licensed under the MIT License.
2016-07-25 14:01:41 -07:00
Describe "Format-Table" -Tags "CI" {
2021-07-19 21:02:52 -07:00
BeforeAll {
if ( $null -ne $PSStyle ) {
$outputRendering = $PSStyle . OutputRendering
$PSStyle . OutputRendering = 'plaintext'
}
2023-01-31 12:06:29 -08:00
$noConsole = $true
try {
if ([ Console ]:: WindowHeight -ne 0 ) {
$noConsole = $false
}
} catch {
}
2021-07-19 21:02:52 -07:00
}
AfterAll {
if ( $null -ne $PSStyle ) {
$PSStyle . OutputRendering = $outputRendering
}
}
2018-04-17 10:06:39 +05:00
It "Should call format table on piped input without error" {
{ Get-Date | Format-Table } | Should -Not -Throw
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Should return a format object data type" {
$val = Get-Date | Format-Table | Get-Member
$val2 = Get-Date | Format-Table | Get-Member
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
$val . TypeName | Should -Match "Microsoft.Powershell.Commands.Internal.Format"
$val2 . TypeName | Should -Match "Microsoft.Powershell.Commands.Internal.Format"
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Should be able to be called with optional parameters" {
$v1 = Get-Date | Format-Table *
$v2 = Get-Date | Format-Table -Property Hour
$v3 = Get-Date | Format-Table -GroupBy Hour
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with not existing table with force should throw PipelineStoppedException" {
2020-05-07 13:00:30 +01:00
$obj = New-Object -TypeName PSObject
$e = { $obj | Format-Table -View bar -Force -ErrorAction Stop } |
2018-04-17 10:06:39 +05:00
Should -Throw -ErrorId "FormatViewNotFound,Microsoft.PowerShell.Commands.FormatTableCommand" -PassThru
$e . CategoryInfo | Should -Match "PipelineStoppedException"
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with array should work" {
$al = ( 0 . .255 )
$info = @ {}
$info . array = $al
$result = $info | Format-Table | Out-String
2018-12-11 13:56:46 -08:00
$result | Should -Match "array\s+{0, 1, 2, 3`u{2026}}" # ellipsis
2018-04-17 10:06:39 +05:00
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with Negative Count should work" {
$FormatEnumerationLimit = -1
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1, 2}"
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
# Pending on issue#888
It "Format-Table with Zero Count should work" -Pending {
$FormatEnumerationLimit = 0
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{...}"
}
2015-08-04 00:31:30 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with Less Count should work" {
$FormatEnumerationLimit = 1
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1...}"
}
2016-04-25 20:16:25 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with More Count should work" {
$FormatEnumerationLimit = 10
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1, 2}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with Equal Count should work" {
$FormatEnumerationLimit = 2
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1, 2}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
# Pending on issue#888
It "Format-Table with Bogus Count should throw Exception" -Pending {
$FormatEnumerationLimit = "abc"
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1, 2}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
# Pending on issue#888
It "Format-Table with Var Deleted should throw Exception" -Pending {
$FormatEnumerationLimit = 2
Remove-Variable FormatEnumerationLimit
2020-05-07 13:00:30 +01:00
$result = Format-Table -InputObject @ { 'test' = 1 , 2 }
2018-04-17 10:06:39 +05:00
$resultStr = $result | Out-String
$resultStr | Should -Match "test\s+{1, 2}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with new line should work" {
$info = @ {}
$info . name = "1\n2"
$result = $info | Format-Table | Out-String
$result | Should -Match "name\s+1.+2"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with ExposeBug920454 should work" {
$IP1 = [ System.Net.IPAddress ]:: Parse ( "1.1.1.1" )
$IP2 = [ System.Net.IPAddress ]:: Parse ( "4fde:0000:0000:0002:0022:f376:255.59.171.63" )
$IPs = New-Object System . Collections . ArrayList
$IPs . Add ( $IP1 )
$IPs . Add ( $IP2 )
$info = @ {}
$info . test = $IPs
$result = $info | Format-Table | Out-String
$result | Should -Match "test\s+{1.1.1.1, 4fde::2:22:f376:ff3b:ab3f}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with Autosize should work" {
$IP1 = [ PSCustomObject ] @ { 'name' = 'Bob' ; 'size' = 1234 ; 'booleanValue' = $true ;}
$IP2 = [ PSCustomObject ] @ { 'name' = 'Jim' ; 'size' = 5678 ; 'booleanValue' = $false ;}
$IPs = New-Object System . Collections . ArrayList
$IPs . Add ( $IP1 )
$IPs . Add ( $IP2 )
2020-05-07 13:00:30 +01:00
$result = $IPs | Format-Table -AutoSize | Out-String
2018-04-17 10:06:39 +05:00
$result | Should -Match "name size booleanValue"
$result | Should -Match "---- ---- ------------"
$result | Should -Match "Bob\s+1234\s+True"
$result | Should -Match "Jim\s+5678\s+False"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with '<testName>' should return `$ null" -TestCases @ (
@ { testName = "empty array" ; testObject = @ {} },
@ { testName = "null" ; testObject = $null }
) {
param ( $testObject )
$result = $testObject | Format-Table -Property "foo" , "bar" | Out-String
$result | Should -BeNullOrEmpty
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with '<testName>' string and -Force should output table with requested properties" -TestCases @ (
@ { testName = "single line" ; testString = "single line string" },
@ { testName = "multi line" ; testString = "line1 `n line2" },
@ { testName = "array" ; testString = "line1" , "line2" }
) {
param ( $testString )
2020-03-24 11:38:45 -07:00
$result = $testString | Format-Table -Property "fox" , "bar" -Force | Out-String
$result . Replace ( " " , "" ). Replace ([ Environment ]:: NewLine , "" ) | Should -BeExactly "foxbar------"
2018-04-17 10:06:39 +05:00
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with complex object for End-To-End should work" {
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thu,Fri,Sat}"
$eto = New-Object MyDayOfWeek
$info = @ {}
$info . intArray = 1 , 2 , 3 , 4
$info . arrayList = "string1" , "string2"
$info . enumerable = [ MyDayOfWeek ] $eto
$info . enumerableTestObject = $eto
$result = $info | Format-Table | Out-String
$result | Should -Match "intArray\s+{1, 2, 3, 4}"
$result | Should -Match "arrayList\s+{string1, string2}"
$result | Should -Match "enumerable\s+Sun"
$result | Should -Match "enumerableTestObject\s+Sun"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table with Expand Enumerable should work" {
$obj1 = "x 0" , "y 0"
$obj2 = "x 1" , "y 1"
$objs = New-Object System . Collections . ArrayList
$objs . Add ( $obj1 )
$objs . Add ( $obj2 )
$mo = [ PSCustomObject ] @ { name = "this is name" ; sub = $objs }
$result1 = $mo | Format-Table -Expand CoreOnly | Out-String
$result1 | Should -Match "name\s+sub"
$result1 | Should -Match "this is name"
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
$result2 = $mo | Format-Table -Expand EnumOnly | Out-String
$result2 | Should -Match "name\s+sub"
$result2 | Should -Match "this is name\s+{x 0 y 0, x 1 y 1}"
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
$result3 = $mo | Format-Table -Expand Both | Out-String
$result3 | Should -Match "name\s+sub"
$result3 | Should -Match "this is name\s+{x 0 y 0, x 1 y 1}"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table should not add trailing whitespace to the header" {
$out = "hello" | Format-Table -Property foo -Force | Out-String
$out . Replace ([ System.Environment ]:: NewLine , "" ) | Should -BeExactly "foo---"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table should not add trailing whitespace to rows" {
$out = [ pscustomobject ] @ { a = 1 ; b = 2 } | Format-Table -HideTableHeaders | Out-String
$out . Replace ([ System.Environment ]:: NewLine , "" ) | Should -BeExactly "1 2"
}
2016-05-13 18:23:28 -07:00
2018-04-17 10:06:39 +05:00
It "Format-Table should have correct alignment" {
$ps1xml = @"
2018-02-26 12:43:31 -08:00
<Configuration>
2018-04-17 10:06:39 +05:00
<ViewDefinitions>
<View>
<Name>Test.Format</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Left</Label>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Center</Label>
<Alignment>center</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Right</Label>
<Alignment>right</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Left</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Center</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Right</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
2018-02-26 12:43:31 -08:00
</Configuration>
"@
2018-10-12 11:31:21 -07:00
$ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "alignment.format.ps1xml"
2018-04-17 10:06:39 +05:00
Set-Content -Path $ps1xmlPath -Value $ps1xml
# run in own runspace so not affect global sessionstate
$ps = [ powershell ]:: Create ()
$ps . AddScript ( {
param ( $ps1xmlPath )
Update-FormatData -AppendPath $ps1xmlPath
$a = [ PSCustomObject ] @ { Left = 1 ; Center = 2 ; Right = 3 }
$a . PSObject . TypeNames . Insert ( 0 , "Test.Format" )
$a | Out-String
} ). AddArgument ( $ps1xmlPath ) | Out-Null
$output = $ps . Invoke ()
2018-02-26 12:43:31 -08:00
2018-04-17 10:06:39 +05:00
$expectedTable = @"
2018-02-26 12:43:31 -08:00
Left Center Right
---- ------ -----
1 2 3
"@
2018-04-17 10:06:39 +05:00
$output . Replace ( " `n " , "" ). Replace ( " `r " , "" ) | Should -BeExactly $expectedTable . Replace ( " `n " , "" ). Replace ( " `r " , "" )
}
2018-02-26 12:43:31 -08:00
2018-04-17 10:06:39 +05:00
It "Format-Table should not have trailing whitespace if there is truncation: <view>" -TestCases @ (
# `u{2B758} is a double-byte Japanese character
2018-12-11 13:56:46 -08:00
# `u{2026} is the ellipsis
@ { view = "Test.Format.Left" ; object =[ pscustomobject ] @ { Left = "123`u{2B758}" } ; expected = "Left----123`u{2026}" },
@ { view = "Test.Format.Center" ; object =[ pscustomobject ] @ { Center = "12345`u{2B758}" }; expected = "Center------12345`u{2026}" }
2018-04-17 10:06:39 +05:00
) {
param ( $view , $object , $expected )
2018-02-26 12:43:31 -08:00
2018-04-17 10:06:39 +05:00
$ps1xml = @"
2018-02-26 12:43:31 -08:00
<Configuration>
2018-04-17 10:06:39 +05:00
<ViewDefinitions>
<View>
<Name>Test.Format.Left</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Left</Label>
<Alignment>left</Alignment>
<Width>4</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Left</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>Test.Format.Center</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Center</Label>
<Alignment>center</Alignment>
<Width>6</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Center</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
2018-02-26 12:43:31 -08:00
</Configuration>
"@
2018-10-12 11:31:21 -07:00
$ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "truncation.format.ps1xml"
2018-04-17 10:06:39 +05:00
Set-Content -Path $ps1xmlPath -Value $ps1xml
# run in own runspace so not affect global sessionstate
$ps = [ powershell ]:: Create ()
$ps . AddScript ( {
param ( $ps1xmlPath , $view , $object )
Update-FormatData -AppendPath $ps1xmlPath
$object . PSObject . TypeNames . Insert ( 0 , "Test.Format" )
$object | Format-Table -View $view | Out-String
} ). AddArgument ( $ps1xmlPath ). AddArgument ( $view ). AddArgument ( $object ) | Out-Null
$output = $ps . Invoke ()
$output . Replace ( " `n " , "" ). Replace ( " `r " , "" ) | Should -BeExactly $expected
}
2018-04-03 12:24:23 +09:00
2018-04-17 10:06:39 +05:00
It "Format-Table should correctly render headers that span multiple rows: <variation>" -TestCases @ (
2018-05-02 05:59:48 -07:00
@ { view = "Default" ; widths = 7 , 7 , 7 ; variation = "2 row, 1 row, 1 row" ; expectedTable = @"
LongLon Header2 Header3
gHeader
------- ------- -------
1 2 3
"@ },
2018-04-17 10:06:39 +05:00
@ { view = "Default" ; widths = 4 , 7 , 4 ; variation = "4 row, 1 row, 2 row" ; expectedTable = @"
2018-04-03 12:24:23 +09:00
Long Header2 Head
Long er3
Head
er
---- ------- ----
1 2 3
"@ },
2018-04-17 10:06:39 +05:00
@ { view = "Default" ; widths = 4 , 4 , 7 ; variation = "4 row, 2 row, 1 row" ; expectedTable = @"
2018-04-03 12:24:23 +09:00
Long Head Header3
Long er2
Head
er
---- ---- -------
1 2 3
"@ },
2018-04-17 10:06:39 +05:00
@ { view = "Default" ; widths = 14 , 7 , 3 ; variation = "1 row, 1 row, 3 row" ; expectedTable = @"
2018-04-03 12:24:23 +09:00
LongLongHeader Header2 Hea
der
3
-------------- ------- ---
1 2 3
"@ },
2018-04-17 10:06:39 +05:00
@ { view = "One" ; widths = 4 , 1 , 1 ; variation = "1 column" ; expectedTable = @"
2018-04-03 12:24:23 +09:00
Long
Long
Head
er
----
1
"@ }
2018-04-17 10:06:39 +05:00
) {
param ( $view , $widths , $expectedTable )
$ps1xml = @"
2018-04-03 12:24:23 +09:00
<Configuration>
2018-04-17 10:06:39 +05:00
<ViewDefinitions>
<View>
<Name>Default</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>LongLongHeader</Label>
<Width>{0}</Width>
</TableColumnHeader>
<TableColumnHeader>
<Label>Header2</Label>
<Width>{1}</Width>
</TableColumnHeader>
<TableColumnHeader>
<Label>Header3</Label>
<Width>{2}</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>First</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Second</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Third</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>One</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>LongLongHeader</Label>
<Width>{0}</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>First</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
2018-04-03 12:24:23 +09:00
</Configuration>
"@
2018-04-17 10:06:39 +05:00
$ps1xml = $ps1xml . Replace ( "{0}" , $widths [ 0 ]). Replace ( "{1}" , $widths [ 1 ]). Replace ( "{2}" , $widths [ 2 ])
2018-10-12 11:31:21 -07:00
$ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "span.format.ps1xml"
2018-04-17 10:06:39 +05:00
Set-Content -Path $ps1xmlPath -Value $ps1xml
# run in own runspace so not affect global sessionstate
$ps = [ powershell ]:: Create ()
$ps . AddScript ( {
param ( $ps1xmlPath , $view )
Update-FormatData -AppendPath $ps1xmlPath
$a = [ PSCustomObject ] @ { First = 1 ; Second = 2 ; Third = 3 }
$a . PSObject . TypeNames . Insert ( 0 , "Test.Format" )
$a | Format-Table -View $view | Out-String
} ). AddArgument ( $ps1xmlPath ). AddArgument ( $view ) | Out-Null
$output = $ps . Invoke ()
foreach ( $e in $ps . Streams . Error )
{
Write-Verbose $e . ToString () -Verbose
}
$ps . HadErrors | Should -BeFalse
2018-05-02 05:59:48 -07:00
$output . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
2018-04-17 10:06:39 +05:00
}
2018-04-23 12:45:14 +05:00
It "Format-Table should correctly render rows: <variation>" -TestCases @ (
@ { view = "Default" ; widths = 4 , 7 , 5 ; variation = "narrow values" ; values = [ PSCustomObject ] @ { First = 1 ; Second = 2 ; Third = 3 }; wrap = $false ; expectedTable = @"
Long*Header2*Heade
2018-12-21 23:57:44 -08:00
Long**********r3
2018-04-23 12:45:14 +05:00
Head
er
----*-------*-----
1**********2***3
"@ },
@ { view = "Default" ; widths = 4 , 7 , 5 ; variation = "narrow values with wrap" ; values = [ PSCustomObject ] @ { First = 1 ; Second = 2 ; Third = 3 }; wrap = $true ; expectedTable = @"
Long*Header2*Heade
2018-12-21 23:57:44 -08:00
Long**********r3
2018-04-23 12:45:14 +05:00
Head
er
----*-------*-----
2018-12-21 23:57:44 -08:00
1**********2***3
2018-04-23 12:45:14 +05:00
"@ },
@ { view = "Default" ; widths = 4 , 7 , 5 ; variation = "wide values" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $false ; expectedTable = @"
Long*Header2*Heade
2018-12-21 23:57:44 -08:00
Long**********r3
2018-04-23 12:45:14 +05:00
Head
er
----*-------*-----
2018-12-11 13:56:46 -08:00
123`u{2026}*`u{2026}345678*1234`u{2026}
2018-04-23 12:45:14 +05:00
"@ },
@ { view = "One" ; widths = 3 , 1 , 1 ; variation = "wide values, 1 column" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $false ; expectedTable = @"
Lon
gLo
ngH
ead
er
---
2018-12-11 13:56:46 -08:00
12`u{2026}
2018-04-23 12:45:14 +05:00
"@ },
@ { view = "Default" ; widths = 4 , 8 , 6 ; variation = "wide values with wrap, 1st column" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $true ; expectedTable = @"
Long**Header2*Header
2018-12-21 23:57:44 -08:00
Long************3
2018-04-23 12:45:14 +05:00
Head
er
----**-------*------
1234*12345678*123456
5
"@ },
@ { view = "Default" ; widths = 5 , 7 , 6 ; variation = "wide values with wrap, 2nd column" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $true ; expectedTable = @"
LongL*Header2*Header
2018-12-21 23:57:44 -08:00
ongHe***********3
2018-04-23 12:45:14 +05:00
ader
-----*-------*------
12345*1234567*123456
************8
"@ },
@ { view = "Default" ; widths = 5 , 8 , 5 ; variation = "wide values with wrap, 3rd column" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $true ; expectedTable = @"
LongL**Header2*Heade
2018-12-21 23:57:44 -08:00
ongHe***********r3
2018-04-23 12:45:14 +05:00
ader
-----**-------*-----
12345*12345678*12345
2018-12-21 23:57:44 -08:00
*****************6
2018-04-23 12:45:14 +05:00
"@ },
@ { view = "Default" ; widths = 4 , 7 , 5 ; variation = "wide values with wrap, all 3 columns" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $true ; expectedTable = @"
Long*Header2*Heade
2018-12-21 23:57:44 -08:00
Long**********r3
2018-04-23 12:45:14 +05:00
Head
er
----*-------*-----
1234*1234567*12345
2018-12-21 23:57:44 -08:00
5**********8***6
2018-04-23 12:45:14 +05:00
"@ },
@ { view = "One" ; widths = 3 , 1 , 1 ; variation = "wide values with wrap, with 1 column" ; values = [ PSCustomObject ] @ { First = "12345" ; Second = "12345678" ; Third = "123456" }; wrap = $true ; expectedTable = @"
Lon
gLo
ngH
ead
er
---
123
45
"@ }
) {
param ( $view , $widths , $values , $wrap , $expectedTable )
$ps1xml = @"
<Configuration>
<ViewDefinitions>
<View>
<Name>Default</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Alignment>left</Alignment>
<Label>LongLongHeader</Label>
<Width>{0}</Width>
</TableColumnHeader>
<TableColumnHeader>
<Alignment>right</Alignment>
<Label>Header2</Label>
<Width>{1}</Width>
</TableColumnHeader>
<TableColumnHeader>
<Alignment>center</Alignment>
<Label>Header3</Label>
<Width>{2}</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>First</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Second</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Third</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>One</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>LongLongHeader</Label>
<Width>{0}</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>First</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
"@
$ps1xml = $ps1xml . Replace ( "{0}" , $widths [ 0 ]). Replace ( "{1}" , $widths [ 1 ]). Replace ( "{2}" , $widths [ 2 ])
2018-10-12 11:31:21 -07:00
$ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "render.format.ps1xml"
2018-04-23 12:45:14 +05:00
Set-Content -Path $ps1xmlPath -Value $ps1xml
# run in own runspace so not affect global sessionstate
$ps = [ powershell ]:: Create ()
$ps . AddScript ( {
param ( $ps1xmlPath , $view , $values , $wrap )
Update-FormatData -AppendPath $ps1xmlPath
$values . PSObject . TypeNames . Insert ( 0 , "Test.Format" )
$values | Format-Table -View $view -Wrap: $wrap | Out-String
} ). AddArgument ( $ps1xmlPath ). AddArgument ( $view ). AddArgument ( $values ). AddArgument ( $wrap ) | Out-Null
$output = $ps . Invoke ()
foreach ( $e in $ps . Streams . Error )
{
Write-Verbose $e . ToString () -Verbose
}
$ps . HadErrors | Should -BeFalse
2018-05-02 05:59:48 -07:00
$output . Replace ( " `r " , "" ). Replace ( " " , "*" ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
}
It "Should render header/row correctly where values are wider than header w/ implicit autosize: <variation>" -TestCases @ (
@ { variation = "first column" ; obj = [ pscustomobject ] @ { abc = "1234" ; bcd = "123" },[ pscustomobject ] @ { abc = "1" ; bcd = "1234" }; expectedTable = @"
abc bcd
--- ---
1234 123
1 1234
"@ },
@ { variation = "both columns" ; obj = [ pscustomobject ] @ { abc = "1234" ; bcd = "1234" },[ pscustomobject ] @ { abc = "1" ; bcd = "1" }; expectedTable = @"
abc bcd
--- ---
1234 1234
1 1
"@ },
@ { variation = "second column" ; obj = [ pscustomobject ] @ { abc = "123" ; bcd = "1234" },[ pscustomobject ] @ { abc = "1" ; bcd = "123" }; expectedTable = @"
abc bcd
--- ---
123 1234
1 123
2018-06-26 00:35:22 -07:00
"@ }
) {
param ( $obj , $expectedTable )
$output = $obj | Format-Table | Out-String
$output . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
}
It "Should render header correctly where header is shorter than column width with justification: <variation>" -TestCases @ (
@ { variation = "left/right" ; obj = [ PSCustomObject ] @ { a = "abc" ; b = 123 }; expectedTable = @"
a b
- -
abc 123
"@ },
@ { variation = "left/left" ; obj = [ PSCustomObject ] @ { a = "abc" ; b = "abc" }; expectedTable = @"
a b
- -
abc abc
"@ },
@ { variation = "right/left" ; obj = [ PSCustomObject ] @ { a = 123 ; b = "abc" }; expectedTable = @"
a b
- -
123 abc
"@ },
@ { variation = "right/right" ; obj = [ PSCustomObject ] @ { a = 123 ; b = 123 }; expectedTable = @"
a b
- -
123 123
2018-05-02 05:59:48 -07:00
"@ }
) {
param ( $obj , $expectedTable )
$output = $obj | Format-Table | Out-String
$output . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
2018-04-23 12:45:14 +05:00
}
2018-06-26 22:24:03 -07:00
It "Should render rows correctly when wrapped: <variation>" -TestCases @ (
@ { variation = "right" ; obj = [ pscustomobject ] @ { A = 1 ; B = 2 ; Name = "This `n Is some random `n multiline content" }; expectedTable = @"
A B Name
- - ----
1 2 This
Is some random
multiline content
"@ },
@ { variation = "left" ; obj = [ pscustomobject ] @ { Name = "This `n Is some random `n multiline content" ; A = 1 ; B = 2 }; expectedTable = @"
Name A B
---- - -
This 1 2
Is some random
multiline content
"@ },
@ { variation = "middle" ; obj = [ pscustomobject ] @ { A = 1 ; Name = "This `n Is some random `n multiline content" ; B = 2 }; expectedTable = @"
A Name B
- ---- -
1 This 2
Is some random
multiline content
"@ }
) {
param ( $obj , $expectedTable )
$output = $obj | Format-Table -Wrap | Out-String
$output . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
}
2018-08-07 15:27:42 -07:00
It "Should not return null when the Console width is equal to 0" {
[ system.management.automation.internal.internaltesthooks ]:: SetTestHook ( 'SetConsoleWidthToZero' , $true )
try
{
# Fill the console window with the string, so that it reaches its max width.
# Check if the max width is equal to default value (120), to test test hook set.
$testObject = @ { test = '1' * 200 }
2020-05-07 13:00:30 +01:00
Format-Table -InputObject $testObject | Out-String -Stream | ForEach-Object { $_ . length } | Sort-Object -Bottom 1 | Should -Be 120
2018-08-07 15:27:42 -07:00
}
finally {
[ system.management.automation.internal.internaltesthooks ]:: SetTestHook ( 'SetConsoleWidthToZero' , $false )
}
}
2018-12-20 11:05:34 -08:00
2023-01-31 12:06:29 -08:00
It "-RepeatHeader should output the header at every screen full" -Skip: $noConsole {
2018-12-20 11:05:34 -08:00
$numHeaders = 4
$numObjects = [ Console ]:: WindowHeight * $numHeaders
$out = 1 .. $numObjects | ForEach-Object { @ { foo = $_ } } | Format-Table -RepeatHeader | Out-String
$lines = $out . Split ([ System.Environment ]:: NewLine )
( $lines | Select-String "Name\s*Value" ). Count | Should -Be ( $numHeaders + 1 )
}
2018-12-21 23:57:44 -08:00
2023-01-31 12:06:29 -08:00
It "-RepeatHeader should output the header at every screen full for custom table" -Skip: $noConsole {
2022-12-30 23:00:00 -08:00
$numHeaders = 4
$numObjects = [ Console ]:: WindowHeight * $numHeaders
$out = 1 .. $numObjects | ForEach-Object { [ pscustomobject ] @ { foo = $_ ; bar = $_ ; hello = $_ ; world = $_ } } | Format-Table -Property hello , world -RepeatHeader | Out-String
$lines = $out . Split ([ System.Environment ]:: NewLine )
( $lines | Select-String "Hello\s*World" ). Count | Should -Be ( $numHeaders + 1 )
}
2018-12-21 23:57:44 -08:00
It "Should be formatted correctly if width is declared and using center alignment" {
$expectedTable = @"
one
---
1
"@
$output = [ pscustomobject ] @ { one = 1 } | Format-Table @ { l = 'one' ; e = 'one' ; width = 10 ; alignment = 'center' } | Out-String
$output . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" ) | Should -BeExactly $expectedTable . Replace ( " `r " , "" ). Replace ( " " , "." ). Replace ( " `n " , "^" )
}
2019-12-04 19:09:56 -08:00
It "Should be formatted correctly with double byte wide chars" {
$obj = [ pscustomobject ] @ {
"哇" = "62" ;
"dbda" = "KM" ;
"消息" = "千"
}
$expected = @"
哇 dbda 消息
-- ---- ----
62 KM 千
"@
2020-01-08 13:33:28 -08:00
$actual = $obj | Format-Table | Out-String
( $actual . Replace ( " `r`n " , " `n " )) | Should -BeExactly ( $expected . Replace ( " `r`n " , " `n " ))
2019-12-04 19:09:56 -08:00
}
2022-07-18 14:27:06 -07:00
It 'Table should format floats, doubles, and decimals with number of decimals from current culture' {
$o = [ PSCustomObject ] @ {
double = [ double ] 1234.56789
float = [ float ] 9876.54321
decimal = [ decimal ] 4567.123456789
}
$table = $o | Format-Table | Out-String
$line = foreach ( $line in $table . split ([ System.Environment ]:: NewLine )) { if ( $line -match '^1234' ) { $line } }
$line | Should -Not -BeNullOrEmpty
$expectedDecimals = ( Get-Culture ). NumberFormat . NumberDecimalDigits
foreach ( $num in $line . split ( ' ' , [ System.StringSplitOptions ]:: RemoveEmptyEntries )) {
$numDecimals = $num . length - $num . indexOf (( Get-Culture ). NumberFormat . NumberDecimalSeparator ) - 1
$numDecimals | Should -Be $expectedDecimals -Because $num
}
}
2024-02-26 11:44:30 -08:00
It 'Works for empty column header label' {
$ps1xml = @'
<Configuration>
<ViewDefinitions>
<View>
<Name>Test.Header.Empty</Name>
<ViewSelectedBy>
<TypeName>Test.Format</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label></Label>
<Width>4</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Prop</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
'@
$ps1xmlPath = Join-Path -Path $TestDrive -ChildPath 'empty.format.ps1xml'
Set-Content -Path $ps1xmlPath -Value $ps1xml
$object = [ pscustomobject ] @ { Prop = '123' }
# run in own runspace so not affect global sessionstate
$ps = [ powershell ]:: Create ()
$ps . AddScript ( {
param ( $ps1xmlPath , $object )
Update-FormatData -AppendPath $ps1xmlPath
$object . PSObject . TypeNames . Insert ( 0 , 'Test.Format' )
$object | Format-Table | Out-String
} ). AddArgument ( $ps1xmlPath ). AddArgument ( $object ) | Out-Null
$output = $ps . Invoke ()
$expected = @"
Prop----123
"@
$output . Replace ( " `n " , "" ). Replace ( " `r " , "" ) | Should -BeExactly $expected
}
2018-04-23 12:45:14 +05:00
}
2021-07-19 21:02:52 -07:00
2022-10-17 15:27:24 -07:00
Describe 'Table color tests' -Tag 'CI' {
2021-08-16 14:17:07 -07:00
BeforeAll {
$originalRendering = $PSStyle . OutputRendering
$PSStyle . OutputRendering = 'Ansi'
}
AfterAll {
$PSStyle . OutputRendering = $originalRendering
}
2022-10-03 15:05:11 -07:00
It 'Table header should use TableHeader' {
2023-03-13 15:40:27 -07:00
$expected = @ (
""
" $( $PSStyle . Formatting . TableHeader ) foo $( $PSStyle . Reset ) "
" $( $PSStyle . Formatting . TableHeader ) --- $( $PSStyle . Reset ) "
" 1"
""
)
$actual = [ pscustomobject ] @ { foo = 1 } | Format-Table | Out-String -Stream
$actual | Should -BeExactly $expected
2021-07-19 21:02:52 -07:00
}
2025-12-05 13:54:52 +09:00
Context 'ExcludeProperty parameter' {
It 'Should exclude specified properties' {
$obj = [ pscustomobject ] @ { Name = 'Test' ; Age = 30 ; City = 'Seattle' }
$result = $obj | Format-Table -ExcludeProperty Age | Out-String
$result | Should -Match 'Name'
$result | Should -Match 'City'
$result | Should -Not -Match 'Age'
}
It 'Should work with wildcard patterns' {
$obj = [ pscustomobject ] @ { Prop1 = 1 ; Prop2 = 2 ; Other = 3 }
$result = $obj | Format-Table -ExcludeProperty Prop * | Out-String
$result | Should -Match 'Other'
$result | Should -Not -Match 'Prop1'
$result | Should -Not -Match 'Prop2'
}
It 'Should work without Property parameter (implies -Property *)' {
$obj = [ pscustomobject ] @ { A = 1 ; B = 2 ; C = 3 }
$result = $obj | Format-Table -ExcludeProperty B | Out-String
$result | Should -Match 'A'
$result | Should -Match 'C'
$result | Should -Not -Match 'B'
}
It 'Should work with Property parameter' {
$obj = [ pscustomobject ] @ { Name = 'Test' ; Age = 30 ; City = 'Seattle' ; Country = 'USA' }
$result = $obj | Format-Table -Property Name , Age , City , Country -ExcludeProperty Age | Out-String
$result | Should -Match 'Name'
$result | Should -Match 'City'
$result | Should -Match 'Country'
$result | Should -Not -Match 'Age'
}
It 'Should handle multiple excluded properties' {
$obj = [ pscustomobject ] @ { A = 1 ; B = 2 ; C = 3 ; D = 4 }
$result = $obj | Format-Table -ExcludeProperty B , D | Out-String
$result | Should -Match 'A'
$result | Should -Match 'C'
$result | Should -Not -Match 'B'
$result | Should -Not -Match 'D'
}
}
2021-07-19 21:02:52 -07:00
}