MegaBites-AI/Windows-powershell
0372
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3Describe "Format-Table" -Tags "CI" {4 BeforeAll {5 if ($null -ne $PSStyle) {6 $outputRendering = $PSStyle.OutputRendering7 $PSStyle.OutputRendering = 'plaintext'8 }9 $noConsole = $true10 try {11 if ([Console]::WindowHeight -ne 0) {12 $noConsole = $false13 }14 } catch {15 }16 }17 18 AfterAll {19 if ($null -ne $PSStyle) {20 $PSStyle.OutputRendering = $outputRendering21 }22 }23 24 It "Should call format table on piped input without error" {25 { Get-Date | Format-Table } | Should -Not -Throw26 }27 28 It "Should return a format object data type" {29 $val = Get-Date | Format-Table | Get-Member30 $val2 = Get-Date | Format-Table | Get-Member31 32 $val.TypeName | Should -Match "Microsoft.Powershell.Commands.Internal.Format"33 $val2.TypeName | Should -Match "Microsoft.Powershell.Commands.Internal.Format"34 }35 36 It "Should be able to be called with optional parameters" {37 $v1 = Get-Date | Format-Table *38 $v2 = Get-Date | Format-Table -Property Hour39 $v3 = Get-Date | Format-Table -GroupBy Hour40 }41 42 It "Format-Table with not existing table with force should throw PipelineStoppedException"{43 $obj = New-Object -TypeName PSObject44 $e = { $obj | Format-Table -View bar -Force -ErrorAction Stop } |45 Should -Throw -ErrorId "FormatViewNotFound,Microsoft.PowerShell.Commands.FormatTableCommand" -PassThru46 $e.CategoryInfo | Should -Match "PipelineStoppedException"47 }48 49 It "Format-Table with array should work" {50 $al = (0..255)51 $info = @{}52 $info.array = $al53 $result = $info | Format-Table | Out-String54 $result | Should -Match "array\s+{0, 1, 2, 3`u{2026}}" # ellipsis55 }56 57 It "Format-Table with Negative Count should work" {58 $FormatEnumerationLimit = -159 $result = Format-Table -InputObject @{'test'= 1, 2}60 $resultStr = $result | Out-String61 $resultStr | Should -Match "test\s+{1, 2}"62 }63 64 # Pending on issue#88865 It "Format-Table with Zero Count should work" -Pending {66 $FormatEnumerationLimit = 067 $result = Format-Table -InputObject @{'test'= 1, 2}68 $resultStr = $result | Out-String69 $resultStr | Should -Match "test\s+{...}"70 }71 72 It "Format-Table with Less Count should work" {73 $FormatEnumerationLimit = 174 $result = Format-Table -InputObject @{'test'= 1, 2}75 $resultStr = $result | Out-String76 $resultStr | Should -Match "test\s+{1...}"77 }78 79 It "Format-Table with More Count should work" {80 $FormatEnumerationLimit = 1081 $result = Format-Table -InputObject @{'test'= 1, 2}82 $resultStr = $result | Out-String83 $resultStr | Should -Match "test\s+{1, 2}"84 }85 86 It "Format-Table with Equal Count should work" {87 $FormatEnumerationLimit = 288 $result = Format-Table -InputObject @{'test'= 1, 2}89 $resultStr = $result | Out-String90 $resultStr | Should -Match "test\s+{1, 2}"91 }92 93 # Pending on issue#88894 It "Format-Table with Bogus Count should throw Exception" -Pending {95 $FormatEnumerationLimit = "abc"96 $result = Format-Table -InputObject @{'test'= 1, 2}97 $resultStr = $result|Out-String98 $resultStr | Should -Match "test\s+{1, 2}"99 }100 101 # Pending on issue#888102 It "Format-Table with Var Deleted should throw Exception" -Pending {103 $FormatEnumerationLimit = 2104 Remove-Variable FormatEnumerationLimit105 $result = Format-Table -InputObject @{'test'= 1, 2}106 $resultStr = $result | Out-String107 $resultStr | Should -Match "test\s+{1, 2}"108 }109 110 It "Format-Table with new line should work" {111 $info = @{}112 $info.name = "1\n2"113 $result = $info | Format-Table | Out-String114 $result | Should -Match "name\s+1.+2"115 }116 117 It "Format-Table with ExposeBug920454 should work" {118 $IP1 = [System.Net.IPAddress]::Parse("1.1.1.1")119 $IP2 = [System.Net.IPAddress]::Parse("4fde:0000:0000:0002:0022:f376:255.59.171.63")120 $IPs = New-Object System.Collections.ArrayList121 $IPs.Add($IP1)122 $IPs.Add($IP2)123 $info = @{}124 $info.test = $IPs125 $result = $info | Format-Table | Out-String126 $result | Should -Match "test\s+{1.1.1.1, 4fde::2:22:f376:ff3b:ab3f}"127 }128 129 It "Format-Table with Autosize should work" {130 $IP1 = [PSCustomObject]@{'name'='Bob';'size'=1234;'booleanValue'=$true;}131 $IP2 = [PSCustomObject]@{'name'='Jim';'size'=5678;'booleanValue'=$false;}132 $IPs = New-Object System.Collections.ArrayList133 $IPs.Add($IP1)134 $IPs.Add($IP2)135 $result = $IPs | Format-Table -AutoSize | Out-String136 $result | Should -Match "name size booleanValue"137 $result | Should -Match "---- ---- ------------"138 $result | Should -Match "Bob\s+1234\s+True"139 $result | Should -Match "Jim\s+5678\s+False"140 }141 142 It "Format-Table with '<testName>' should return `$null" -TestCases @(143 @{ testName = "empty array"; testObject = @{} },144 @{ testName = "null" ; testObject = $null }145 ) {146 param ($testObject)147 $result = $testObject | Format-Table -Property "foo","bar" | Out-String148 $result | Should -BeNullOrEmpty149 }150 151 It "Format-Table with '<testName>' string and -Force should output table with requested properties" -TestCases @(152 @{ testName = "single line"; testString = "single line string" },153 @{ testName = "multi line" ; testString = "line1`nline2" },154 @{ testName = "array" ; testString = "line1","line2" }155 ) {156 param ($testString)157 $result = $testString | Format-Table -Property "fox","bar" -Force | Out-String158 $result.Replace(" ","").Replace([Environment]::NewLine,"") | Should -BeExactly "foxbar------"159 }160 161 It "Format-Table with complex object for End-To-End should work" {162 Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thu,Fri,Sat}"163 $eto = New-Object MyDayOfWeek164 $info = @{}165 $info.intArray = 1,2,3,4166 $info.arrayList = "string1","string2"167 $info.enumerable = [MyDayOfWeek]$eto168 $info.enumerableTestObject = $eto169 $result = $info|Format-Table|Out-String170 $result | Should -Match "intArray\s+{1, 2, 3, 4}"171 $result | Should -Match "arrayList\s+{string1, string2}"172 $result | Should -Match "enumerable\s+Sun"173 $result | Should -Match "enumerableTestObject\s+Sun"174 }175 176 It "Format-Table with Expand Enumerable should work" {177 $obj1 = "x 0","y 0"178 $obj2 = "x 1","y 1"179 $objs = New-Object System.Collections.ArrayList180 $objs.Add($obj1)181 $objs.Add($obj2)182 $mo = [PSCustomObject]@{name = "this is name";sub = $objs}183 $result1 = $mo|Format-Table -Expand CoreOnly|Out-String184 $result1 | Should -Match "name\s+sub"185 $result1 | Should -Match "this is name"186 187 $result2 = $mo|Format-Table -Expand EnumOnly|Out-String188 $result2 | Should -Match "name\s+sub"189 $result2 | Should -Match "this is name\s+{x 0 y 0, x 1 y 1}"190 191 $result3 = $mo|Format-Table -Expand Both|Out-String192 $result3 | Should -Match "name\s+sub"193 $result3 | Should -Match "this is name\s+{x 0 y 0, x 1 y 1}"194 }195 196 It "Format-Table should not add trailing whitespace to the header" {197 $out = "hello" | Format-Table -Property foo -Force | Out-String198 $out.Replace([System.Environment]::NewLine, "") | Should -BeExactly "foo---"199 }200 201 It "Format-Table should not add trailing whitespace to rows" {202 $out = [pscustomobject]@{a=1;b=2} | Format-Table -HideTableHeaders | Out-String203 $out.Replace([System.Environment]::NewLine, "") | Should -BeExactly "1 2"204 }205 206 It "Format-Table should have correct alignment" {207 $ps1xml = @"208<Configuration>209 <ViewDefinitions>210 <View>211 <Name>Test.Format</Name>212 <ViewSelectedBy>213 <TypeName>Test.Format</TypeName>214 </ViewSelectedBy>215 <TableControl>216 <TableHeaders>217 <TableColumnHeader>218 <Label>Left</Label>219 <Alignment>left</Alignment>220 </TableColumnHeader>221 <TableColumnHeader>222 <Label>Center</Label>223 <Alignment>center</Alignment>224 </TableColumnHeader>225 <TableColumnHeader>226 <Label>Right</Label>227 <Alignment>right</Alignment>228 </TableColumnHeader>229 </TableHeaders>230 <TableRowEntries>231 <TableRowEntry>232 <TableColumnItems>233 <TableColumnItem>234 <PropertyName>Left</PropertyName>235 </TableColumnItem>236 <TableColumnItem>237 <PropertyName>Center</PropertyName>238 </TableColumnItem>239 <TableColumnItem>240 <PropertyName>Right</PropertyName>241 </TableColumnItem>242 </TableColumnItems>243 </TableRowEntry>244 </TableRowEntries>245 </TableControl>246 </View>247 </ViewDefinitions>248</Configuration>249"@250 251 $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "alignment.format.ps1xml"252 Set-Content -Path $ps1xmlPath -Value $ps1xml253 # run in own runspace so not affect global sessionstate254 $ps = [powershell]::Create()255 $ps.AddScript( {256 param($ps1xmlPath)257 Update-FormatData -AppendPath $ps1xmlPath258 $a = [PSCustomObject]@{Left=1;Center=2;Right=3}259 $a.PSObject.TypeNames.Insert(0,"Test.Format")260 $a | Out-String261 } ).AddArgument($ps1xmlPath) | Out-Null262 $output = $ps.Invoke()263 264 $expectedTable = @"265 266Left Center Right267---- ------ -----2681 2 3269 270 271 272"@273 $output.Replace("`n","").Replace("`r","") | Should -BeExactly $expectedTable.Replace("`n","").Replace("`r","")274 }275 276 It "Format-Table should not have trailing whitespace if there is truncation: <view>" -TestCases @(277 # `u{2B758} is a double-byte Japanese character278 # `u{2026} is the ellipsis279 @{view="Test.Format.Left" ; object=[pscustomobject]@{Left="123`u{2B758}"} ; expected="Left----123`u{2026}" },280 @{view="Test.Format.Center"; object=[pscustomobject]@{Center="12345`u{2B758}"}; expected="Center------12345`u{2026}"}281 ) {282 param($view, $object, $expected)283 284 $ps1xml = @"285<Configuration>286 <ViewDefinitions>287 <View>288 <Name>Test.Format.Left</Name>289 <ViewSelectedBy>290 <TypeName>Test.Format</TypeName>291 </ViewSelectedBy>292 <TableControl>293 <TableHeaders>294 <TableColumnHeader>295 <Label>Left</Label>296 <Alignment>left</Alignment>297 <Width>4</Width>298 </TableColumnHeader>299 </TableHeaders>300 <TableRowEntries>301 <TableRowEntry>302 <TableColumnItems>303 <TableColumnItem>304 <PropertyName>Left</PropertyName>305 </TableColumnItem>306 </TableColumnItems>307 </TableRowEntry>308 </TableRowEntries>309 </TableControl>310 </View>311 <View>312 <Name>Test.Format.Center</Name>313 <ViewSelectedBy>314 <TypeName>Test.Format</TypeName>315 </ViewSelectedBy>316 <TableControl>317 <TableHeaders>318 <TableColumnHeader>319 <Label>Center</Label>320 <Alignment>center</Alignment>321 <Width>6</Width>322 </TableColumnHeader>323 </TableHeaders>324 <TableRowEntries>325 <TableRowEntry>326 <TableColumnItems>327 <TableColumnItem>328 <PropertyName>Center</PropertyName>329 </TableColumnItem>330 </TableColumnItems>331 </TableRowEntry>332 </TableRowEntries>333 </TableControl>334 </View>335 </ViewDefinitions>336</Configuration>337"@338 339 $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "truncation.format.ps1xml"340 Set-Content -Path $ps1xmlPath -Value $ps1xml341 # run in own runspace so not affect global sessionstate342 $ps = [powershell]::Create()343 $ps.AddScript( {344 param($ps1xmlPath,$view,$object)345 Update-FormatData -AppendPath $ps1xmlPath346 $object.PSObject.TypeNames.Insert(0,"Test.Format")347 $object | Format-Table -View $view | Out-String348 } ).AddArgument($ps1xmlPath).AddArgument($view).AddArgument($object) | Out-Null349 $output = $ps.Invoke()350 $output.Replace("`n","").Replace("`r","") | Should -BeExactly $expected351 }352 353 It "Format-Table should correctly render headers that span multiple rows: <variation>" -TestCases @(354 @{ view = "Default"; widths = 7,7,7; variation = "2 row, 1 row, 1 row"; expectedTable = @"355 356LongLon Header2 Header3357gHeader358------- ------- -------3591 2 3360 361 362"@ },363 @{ view = "Default"; widths = 4,7,4; variation = "4 row, 1 row, 2 row"; expectedTable = @"364 365Long Header2 Head366Long er3367Head368er369---- ------- ----3701 2 3371 372 373"@ },374 @{ view = "Default"; widths = 4,4,7; variation = "4 row, 2 row, 1 row"; expectedTable = @"375 376Long Head Header3377Long er2378Head379er380---- ---- -------3811 2 3382 383 384"@ },385 @{ view = "Default"; widths = 14,7,3; variation = "1 row, 1 row, 3 row"; expectedTable = @"386 387LongLongHeader Header2 Hea388 der389 3390-------------- ------- ---3911 2 3392 393 394"@ },395 @{ view = "One"; widths = 4,1,1; variation = "1 column"; expectedTable = @"396 397Long398Long399Head400er401----4021403 404 405"@ }406 ) {407 param($view, $widths, $expectedTable)408 $ps1xml = @"409<Configuration>410 <ViewDefinitions>411 <View>412 <Name>Default</Name>413 <ViewSelectedBy>414 <TypeName>Test.Format</TypeName>415 </ViewSelectedBy>416 <TableControl>417 <TableHeaders>418 <TableColumnHeader>419 <Label>LongLongHeader</Label>420 <Width>{0}</Width>421 </TableColumnHeader>422 <TableColumnHeader>423 <Label>Header2</Label>424 <Width>{1}</Width>425 </TableColumnHeader>426 <TableColumnHeader>427 <Label>Header3</Label>428 <Width>{2}</Width>429 </TableColumnHeader>430 </TableHeaders>431 <TableRowEntries>432 <TableRowEntry>433 <TableColumnItems>434 <TableColumnItem>435 <PropertyName>First</PropertyName>436 </TableColumnItem>437 <TableColumnItem>438 <PropertyName>Second</PropertyName>439 </TableColumnItem>440 <TableColumnItem>441 <PropertyName>Third</PropertyName>442 </TableColumnItem>443 </TableColumnItems>444 </TableRowEntry>445 </TableRowEntries>446 </TableControl>447 </View>448 <View>449 <Name>One</Name>450 <ViewSelectedBy>451 <TypeName>Test.Format</TypeName>452 </ViewSelectedBy>453 <TableControl>454 <TableHeaders>455 <TableColumnHeader>456 <Label>LongLongHeader</Label>457 <Width>{0}</Width>458 </TableColumnHeader>459 </TableHeaders>460 <TableRowEntries>461 <TableRowEntry>462 <TableColumnItems>463 <TableColumnItem>464 <PropertyName>First</PropertyName>465 </TableColumnItem>466 </TableColumnItems>467 </TableRowEntry>468 </TableRowEntries>469 </TableControl>470 </View>471 </ViewDefinitions>472</Configuration>473"@474 $ps1xml = $ps1xml.Replace("{0}", $widths[0]).Replace("{1}", $widths[1]).Replace("{2}", $widths[2])475 $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "span.format.ps1xml"476 Set-Content -Path $ps1xmlPath -Value $ps1xml477 # run in own runspace so not affect global sessionstate478 $ps = [powershell]::Create()479 $ps.AddScript( {480 param($ps1xmlPath, $view)481 Update-FormatData -AppendPath $ps1xmlPath482 $a = [PSCustomObject]@{First=1;Second=2;Third=3}483 $a.PSObject.TypeNames.Insert(0,"Test.Format")484 $a | Format-Table -View $view | Out-String485 } ).AddArgument($ps1xmlPath).AddArgument($view) | Out-Null486 $output = $ps.Invoke()487 foreach ($e in $ps.Streams.Error)488 {489 Write-Verbose $e.ToString() -Verbose490 }491 $ps.HadErrors | Should -BeFalse492 $output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")493 }494 495 It "Format-Table should correctly render rows: <variation>" -TestCases @(496 @{ view = "Default"; widths = 4,7,5; variation = "narrow values"; values = [PSCustomObject]@{First=1;Second=2;Third=3}; wrap = $false; expectedTable = @"497 498Long*Header2*Heade499Long**********r3500Head501er502----*-------*-----5031**********2***3504 505 506"@ },507 @{ view = "Default"; widths = 4,7,5; variation = "narrow values with wrap"; values = [PSCustomObject]@{First=1;Second=2;Third=3}; wrap = $true; expectedTable = @"508 509Long*Header2*Heade510Long**********r3511Head512er513----*-------*-----5141**********2***3515 516 517"@ },518 @{ view = "Default"; widths = 4,7,5; variation = "wide values"; values = [PSCustomObject]@{First="12345";Second="12345678";Third="123456"}; wrap = $false; expectedTable = @"519 520Long*Header2*Heade521Long**********r3522Head523er524----*-------*-----525123`u{2026}*`u{2026}345678*1234`u{2026}526 527 528"@ },529 @{ view = "One"; widths = 3,1,1; variation = "wide values, 1 column"; values = [PSCustomObject]@{First="12345";Second="12345678";Third="123456"}; wrap = $false; expectedTable = @"530 531Lon532gLo533ngH534ead535er536---53712`u{2026}538 539 540"@ },541 @{ view = "Default"; widths = 4,8,6; variation = "wide values with wrap, 1st column"; values = [PSCustomObject]@{First="12345";Second="12345678";Third="123456"}; wrap = $true; expectedTable = @"542 543Long**Header2*Header544Long************3545Head546er547----**-------*------5481234*12345678*1234565495550 551 552"@ },553 @{ view = "Default"; widths = 5,7,6; variation = "wide values with wrap, 2nd column"; values = [PSCustomObject]@{First="12345";Second="12345678";Third="123456"}; wrap = $true; expectedTable = @"554 555LongL*Header2*Header556ongHe***********3557ader558-----*-------*------55912345*1234567*123456560************8561 562 563"@ },564 @{ view = "Default"; widths = 5,8,5; variation = "wide values with wrap, 3rd column"; values = [PSCustomObject]@{First="12345";Second="12345678";Third="123456"}; wrap = $true; expectedTable = @"565 566LongL**Header2*Heade567ongHe***********r3568ader569-----**-------*-----57012345*12345678*12345571*****************6572 573 574"@ },575 @{ 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 = @"576 577Long*Header2*Heade578Long**********r3579Head580er581----*-------*-----5821234*1234567*123455835**********8***6584 585 586"@ },587 @{ 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 = @"588 589Lon590gLo591ngH592ead593er594---59512359645597 598 599"@ }600 ) {601 param($view, $widths, $values, $wrap, $expectedTable)602 $ps1xml = @"603<Configuration>604 <ViewDefinitions>605 <View>606 <Name>Default</Name>607 <ViewSelectedBy>608 <TypeName>Test.Format</TypeName>609 </ViewSelectedBy>610 <TableControl>611 <TableHeaders>612 <TableColumnHeader>613 <Alignment>left</Alignment>614 <Label>LongLongHeader</Label>615 <Width>{0}</Width>616 </TableColumnHeader>617 <TableColumnHeader>618 <Alignment>right</Alignment>619 <Label>Header2</Label>620 <Width>{1}</Width>621 </TableColumnHeader>622 <TableColumnHeader>623 <Alignment>center</Alignment>624 <Label>Header3</Label>625 <Width>{2}</Width>626 </TableColumnHeader>627 </TableHeaders>628 <TableRowEntries>629 <TableRowEntry>630 <TableColumnItems>631 <TableColumnItem>632 <PropertyName>First</PropertyName>633 </TableColumnItem>634 <TableColumnItem>635 <PropertyName>Second</PropertyName>636 </TableColumnItem>637 <TableColumnItem>638 <PropertyName>Third</PropertyName>639 </TableColumnItem>640 </TableColumnItems>641 </TableRowEntry>642 </TableRowEntries>643 </TableControl>644 </View>645 <View>646 <Name>One</Name>647 <ViewSelectedBy>648 <TypeName>Test.Format</TypeName>649 </ViewSelectedBy>650 <TableControl>651 <TableHeaders>652 <TableColumnHeader>653 <Label>LongLongHeader</Label>654 <Width>{0}</Width>655 </TableColumnHeader>656 </TableHeaders>657 <TableRowEntries>658 <TableRowEntry>659 <TableColumnItems>660 <TableColumnItem>661 <PropertyName>First</PropertyName>662 </TableColumnItem>663 </TableColumnItems>664 </TableRowEntry>665 </TableRowEntries>666 </TableControl>667 </View>668 </ViewDefinitions>669</Configuration>670"@671 $ps1xml = $ps1xml.Replace("{0}", $widths[0]).Replace("{1}", $widths[1]).Replace("{2}", $widths[2])672 $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath "render.format.ps1xml"673 Set-Content -Path $ps1xmlPath -Value $ps1xml674 # run in own runspace so not affect global sessionstate675 $ps = [powershell]::Create()676 $ps.AddScript( {677 param($ps1xmlPath, $view, $values, $wrap)678 Update-FormatData -AppendPath $ps1xmlPath679 $values.PSObject.TypeNames.Insert(0,"Test.Format")680 $values | Format-Table -View $view -Wrap:$wrap | Out-String681 } ).AddArgument($ps1xmlPath).AddArgument($view).AddArgument($values).AddArgument($wrap) | Out-Null682 $output = $ps.Invoke()683 foreach ($e in $ps.Streams.Error)684 {685 Write-Verbose $e.ToString() -Verbose686 }687 $ps.HadErrors | Should -BeFalse688 $output.Replace("`r","").Replace(" ","*").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")689 }690 691 It "Should render header/row correctly where values are wider than header w/ implicit autosize: <variation>" -TestCases @(692 @{ variation = "first column"; obj = [pscustomobject]@{abc="1234";bcd="123"},[pscustomobject]@{abc="1";bcd="1234"}; expectedTable = @"693 694abc bcd695--- ---6961234 1236971 1234698 699 700"@ },701 @{ variation = "both columns"; obj = [pscustomobject]@{abc="1234";bcd="1234"},[pscustomobject]@{abc="1";bcd="1"}; expectedTable = @"702 703abc bcd704--- ---7051234 12347061 1707 708 709"@ },710 @{ variation = "second column"; obj = [pscustomobject]@{abc="123";bcd="1234"},[pscustomobject]@{abc="1";bcd="123"}; expectedTable = @"711 712abc bcd713--- ---714123 12347151 123716 717 718"@ }719 ) {720 param($obj, $expectedTable)721 $output = $obj | Format-Table | Out-String722 $output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")723 }724 725 It "Should render header correctly where header is shorter than column width with justification: <variation>" -TestCases @(726 @{ variation = "left/right"; obj = [PSCustomObject]@{a="abc";b=123}; expectedTable = @"727 728a b729- -730abc 123731 732 733"@ },734 @{ variation = "left/left"; obj = [PSCustomObject]@{a="abc";b="abc"}; expectedTable = @"735 736a b737- -738abc abc739 740 741"@ },742 @{ variation = "right/left"; obj = [PSCustomObject]@{a=123;b="abc"}; expectedTable = @"743 744 a b745 - -746123 abc747 748 749"@ },750 @{ variation = "right/right"; obj = [PSCustomObject]@{a=123;b=123}; expectedTable = @"751 752 a b753 - -754123 123755 756 757"@ }758 ) {759 param($obj, $expectedTable)760 $output = $obj | Format-Table | Out-String761 $output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")762 }763 764 It "Should render rows correctly when wrapped: <variation>" -TestCases @(765 @{ variation = "right"; obj = [pscustomobject] @{A=1;B=2;Name="This`nIs some random`nmultiline content"}; expectedTable = @"766 767A B Name768- - ----7691 2 This770 Is some random771 multiline content772 773 774"@ },775 @{ variation = "left"; obj = [pscustomobject] @{Name="This`nIs some random`nmultiline content";A=1;B=2}; expectedTable = @"776 777Name A B778---- - -779This 1 2780Is some random781multiline content782 783 784"@ },785 @{ variation = "middle"; obj = [pscustomobject] @{A=1;Name="This`nIs some random`nmultiline content";B=2}; expectedTable = @"786 787A Name B788- ---- -7891 This 2790 Is some random791 multiline content792 793 794"@ }795 ) {796 param($obj, $expectedTable)797 $output = $obj | Format-Table -Wrap | Out-String798 $output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")799 }800 801 It "Should not return null when the Console width is equal to 0" {802 [system.management.automation.internal.internaltesthooks]::SetTestHook('SetConsoleWidthToZero', $true)803 try804 {805 # Fill the console window with the string, so that it reaches its max width.806 # Check if the max width is equal to default value (120), to test test hook set.807 $testObject = @{ test = '1' * 200}808 Format-Table -InputObject $testObject | Out-String -Stream | ForEach-Object{$_.length} | Sort-Object -Bottom 1 | Should -Be 120809 }810 finally {811 [system.management.automation.internal.internaltesthooks]::SetTestHook('SetConsoleWidthToZero', $false)812 }813 }814 815 It "-RepeatHeader should output the header at every screen full" -Skip:$noConsole {816 $numHeaders = 4817 $numObjects = [Console]::WindowHeight * $numHeaders818 $out = 1..$numObjects | ForEach-Object { @{foo=$_} } | Format-Table -RepeatHeader | Out-String819 $lines = $out.Split([System.Environment]::NewLine)820 ($lines | Select-String "Name\s*Value").Count | Should -Be ($numHeaders + 1)821 }822 823 It "-RepeatHeader should output the header at every screen full for custom table" -Skip:$noConsole {824 $numHeaders = 4825 $numObjects = [Console]::WindowHeight * $numHeaders826 $out = 1..$numObjects | ForEach-Object { [pscustomobject]@{foo=$_;bar=$_;hello=$_;world=$_} } | Format-Table -Property hello, world -RepeatHeader | Out-String827 $lines = $out.Split([System.Environment]::NewLine)828 ($lines | Select-String "Hello\s*World").Count | Should -Be ($numHeaders + 1)829 }830 831 It "Should be formatted correctly if width is declared and using center alignment" {832 $expectedTable = @"833 834 one835 ---836 1837 838 839"@840 $output = [pscustomobject] @{ one = 1 } | Format-Table @{ l='one'; e='one'; width=10; alignment='center' } | Out-String841 $output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")842 }843 844 It "Should be formatted correctly with double byte wide chars" {845 $obj = [pscustomobject]@{846 "哇" = "62";847 "dbda" = "KM";848 "消息" = "千"849 }850 851 $expected = @"852 853哇 dbda 消息854-- ---- ----85562 KM 千856 857 858"@859 860 $actual = $obj | Format-Table | Out-String861 ($actual.Replace("`r`n", "`n")) | Should -BeExactly ($expected.Replace("`r`n", "`n"))862 }863 864 It 'Table should format floats, doubles, and decimals with number of decimals from current culture' {865 $o = [PSCustomObject]@{866 double = [double]1234.56789867 float = [float]9876.54321868 decimal = [decimal]4567.123456789869 }870 871 $table = $o | Format-Table | Out-String872 873 $line = foreach ($line in $table.split([System.Environment]::NewLine)) { if ($line -match '^1234') { $line } }874 $line | Should -Not -BeNullOrEmpty875 $expectedDecimals = (Get-Culture).NumberFormat.NumberDecimalDigits876 877 foreach ($num in $line.split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)) {878 $numDecimals = $num.length - $num.indexOf((Get-Culture).NumberFormat.NumberDecimalSeparator) - 1879 $numDecimals | Should -Be $expectedDecimals -Because $num880 }881 }882 883 It 'Works for empty column header label' {884 $ps1xml = @'885 <Configuration>886 <ViewDefinitions>887 <View>888 <Name>Test.Header.Empty</Name>889 <ViewSelectedBy>890 <TypeName>Test.Format</TypeName>891 </ViewSelectedBy>892 <TableControl>893 <TableHeaders>894 <TableColumnHeader>895 <Label></Label>896 <Width>4</Width>897 </TableColumnHeader>898 </TableHeaders>899 <TableRowEntries>900 <TableRowEntry>901 <TableColumnItems>902 <TableColumnItem>903 <PropertyName>Prop</PropertyName>904 </TableColumnItem>905 </TableColumnItems>906 </TableRowEntry>907 </TableRowEntries>908 </TableControl>909 </View>910 </ViewDefinitions>911 </Configuration>912'@913 914 $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath 'empty.format.ps1xml'915 Set-Content -Path $ps1xmlPath -Value $ps1xml916 $object = [pscustomobject]@{Prop = '123'}917 # run in own runspace so not affect global sessionstate918 $ps = [powershell]::Create()919 $ps.AddScript( {920 param($ps1xmlPath, $object)921 Update-FormatData -AppendPath $ps1xmlPath922 $object.PSObject.TypeNames.Insert(0, 'Test.Format')923 $object | Format-Table | Out-String924 } ).AddArgument($ps1xmlPath).AddArgument($object) | Out-Null925 $output = $ps.Invoke()926 $expected = @"927Prop----123928"@929 $output.Replace("`n","").Replace("`r","") | Should -BeExactly $expected930 }931 }932 933Describe 'Table color tests' -Tag 'CI' {934 BeforeAll {935 $originalRendering = $PSStyle.OutputRendering936 $PSStyle.OutputRendering = 'Ansi'937 }938 939 AfterAll {940 $PSStyle.OutputRendering = $originalRendering941 }942 943 It 'Table header should use TableHeader' {944 $expected = @(945 ""946 "$($PSStyle.Formatting.TableHeader)foo$($PSStyle.Reset)"947 "$($PSStyle.Formatting.TableHeader)---$($PSStyle.Reset)"948 " 1"949 ""950 )951 952 $actual = [pscustomobject]@{foo = 1} | Format-Table | Out-String -Stream953 954 $actual | Should -BeExactly $expected955 }956 957 Context 'ExcludeProperty parameter' {958 It 'Should exclude specified properties' {959 $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle' }960 $result = $obj | Format-Table -ExcludeProperty Age | Out-String961 $result | Should -Match 'Name'962 $result | Should -Match 'City'963 $result | Should -Not -Match 'Age'964 }965 966 It 'Should work with wildcard patterns' {967 $obj = [pscustomobject]@{ Prop1 = 1; Prop2 = 2; Other = 3 }968 $result = $obj | Format-Table -ExcludeProperty Prop* | Out-String969 $result | Should -Match 'Other'970 $result | Should -Not -Match 'Prop1'971 $result | Should -Not -Match 'Prop2'972 }973 974 It 'Should work without Property parameter (implies -Property *)' {975 $obj = [pscustomobject]@{ A = 1; B = 2; C = 3 }976 $result = $obj | Format-Table -ExcludeProperty B | Out-String977 $result | Should -Match 'A'978 $result | Should -Match 'C'979 $result | Should -Not -Match 'B'980 }981 982 It 'Should work with Property parameter' {983 $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle'; Country = 'USA' }984 $result = $obj | Format-Table -Property Name, Age, City, Country -ExcludeProperty Age | Out-String985 $result | Should -Match 'Name'986 $result | Should -Match 'City'987 $result | Should -Match 'Country'988 $result | Should -Not -Match 'Age'989 }990 991 It 'Should handle multiple excluded properties' {992 $obj = [pscustomobject]@{ A = 1; B = 2; C = 3; D = 4 }993 $result = $obj | Format-Table -ExcludeProperty B, D | Out-String994 $result | Should -Match 'A'995 $result | Should -Match 'C'996 $result | Should -Not -Match 'B'997 $result | Should -Not -Match 'D'998 }999 }1000}1001 