Skip to content

Commit 5cc2652

Browse files
committed
Merge branch 'terminal_gui_v2' of tig:tig/GraphicalTools into terminal_gui_v2
2 parents 7e463b5 + a9b8e93 commit 5cc2652

14 files changed

Lines changed: 1227 additions & 2 deletions

.github/workflows/ci-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434

3535
- name: Build and test
3636
shell: pwsh
37-
run: Invoke-Build -Configuration Release Build, Package
37+
run: Invoke-Build -Configuration Release Build, Test, Package
3838

3939
- name: Upload module
4040
if: always()

ConsoleGuiTools.build.ps1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ task Build {
4848
New-ExternalHelp -Path docs/Microsoft.PowerShell.ConsoleGuiTools -OutputPath module/en-US -Force
4949
}
5050

51+
task Test {
52+
Invoke-BuildExec { & dotnet test --configuration $Configuration }
53+
}
54+
5155
task Package {
5256
New-Item -ItemType Directory -Force ./out | Out-Null
5357
if (-Not (Get-PSResourceRepository -Name ConsoleGuiTools -ErrorAction SilentlyContinue)) {
@@ -56,4 +60,4 @@ task Package {
5660
Publish-PSResource -Path ./module -Repository ConsoleGuiTools -Verbose
5761
}
5862

59-
task . Clean, Build
63+
task . Clean, Build, Test

Directory.Packages.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,10 @@
44
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
55
<PackageVersion Include="System.Management.Automation" Version="7.5.4" />
66
<PackageVersion Include="Terminal.Gui" Version="2.0.0-beta.149" />
7+
<!-- Test dependencies -->
8+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
9+
<PackageVersion Include="xunit" Version="2.9.3" />
10+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
11+
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
712
</ItemGroup>
813
</Project>

GraphicalTools.sln

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.ConsoleGuiTools", "src\Microsoft.PowerShell.ConsoleGuiTools\Microsoft.PowerShell.ConsoleGuiTools.csproj", "{DBAF2B0C-2E02-4698-A788-EB7EB6364404}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.OutGridView.Models", "src\Microsoft.PowerShell.OutGridView.Models\Microsoft.PowerShell.OutGridView.Models.csproj", "{233472F8-D472-4265-813B-B394013A2B60}"
11+
EndProject
12+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
13+
EndProject
14+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.ConsoleGuiTools.Tests", "test\Microsoft.PowerShell.ConsoleGuiTools.Tests\Microsoft.PowerShell.ConsoleGuiTools.Tests.csproj", "{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}"
15+
EndProject
16+
Global
17+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
18+
Debug|Any CPU = Debug|Any CPU
19+
Debug|x64 = Debug|x64
20+
Debug|x86 = Debug|x86
21+
Release|Any CPU = Release|Any CPU
22+
Release|x64 = Release|x64
23+
Release|x86 = Release|x86
24+
EndGlobalSection
25+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
26+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|x64.ActiveCfg = Debug|Any CPU
29+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|x64.Build.0 = Debug|Any CPU
30+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|x86.ActiveCfg = Debug|Any CPU
31+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Debug|x86.Build.0 = Debug|Any CPU
32+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|Any CPU.ActiveCfg = Release|Any CPU
33+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|Any CPU.Build.0 = Release|Any CPU
34+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|x64.ActiveCfg = Release|Any CPU
35+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|x64.Build.0 = Release|Any CPU
36+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|x86.ActiveCfg = Release|Any CPU
37+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404}.Release|x86.Build.0 = Release|Any CPU
38+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|Any CPU.Build.0 = Debug|Any CPU
40+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|x64.ActiveCfg = Debug|Any CPU
41+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|x64.Build.0 = Debug|Any CPU
42+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|x86.ActiveCfg = Debug|Any CPU
43+
{233472F8-D472-4265-813B-B394013A2B60}.Debug|x86.Build.0 = Debug|Any CPU
44+
{233472F8-D472-4265-813B-B394013A2B60}.Release|Any CPU.ActiveCfg = Release|Any CPU
45+
{233472F8-D472-4265-813B-B394013A2B60}.Release|Any CPU.Build.0 = Release|Any CPU
46+
{233472F8-D472-4265-813B-B394013A2B60}.Release|x64.ActiveCfg = Release|Any CPU
47+
{233472F8-D472-4265-813B-B394013A2B60}.Release|x64.Build.0 = Release|Any CPU
48+
{233472F8-D472-4265-813B-B394013A2B60}.Release|x86.ActiveCfg = Release|Any CPU
49+
{233472F8-D472-4265-813B-B394013A2B60}.Release|x86.Build.0 = Release|Any CPU
50+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|Any CPU.Build.0 = Debug|Any CPU
52+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|x64.ActiveCfg = Debug|Any CPU
53+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|x64.Build.0 = Debug|Any CPU
54+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|x86.ActiveCfg = Debug|Any CPU
55+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Debug|x86.Build.0 = Debug|Any CPU
56+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|Any CPU.ActiveCfg = Release|Any CPU
57+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|Any CPU.Build.0 = Release|Any CPU
58+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|x64.ActiveCfg = Release|Any CPU
59+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|x64.Build.0 = Release|Any CPU
60+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|x86.ActiveCfg = Release|Any CPU
61+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321}.Release|x86.Build.0 = Release|Any CPU
62+
EndGlobalSection
63+
GlobalSection(SolutionProperties) = preSolution
64+
HideSolutionNode = FALSE
65+
EndGlobalSection
66+
GlobalSection(NestedProjects) = preSolution
67+
{DBAF2B0C-2E02-4698-A788-EB7EB6364404} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
68+
{233472F8-D472-4265-813B-B394013A2B60} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
69+
{F1E2D3C4-B5A6-7890-ABCD-EF0987654321} = {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
70+
EndGlobalSection
71+
EndGlobal

src/Microsoft.PowerShell.ConsoleGuiTools/Microsoft.PowerShell.ConsoleGuiTools.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
<None Update="Microsoft.PowerShell.ConsoleGuiTools.psd1" CopyToOutputDirectory="PreserveNewest" />
3030
</ItemGroup>
3131

32+
<ItemGroup>
33+
<InternalsVisibleTo Include="Microsoft.PowerShell.ConsoleGuiTools.Tests" />
34+
</ItemGroup>
35+
3236
<PropertyGroup>
3337
<EnableNETAnalyzers>true</EnableNETAnalyzers>
3438
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>

src/Microsoft.PowerShell.OutGridView.Models/Microsoft.PowerShell.OutGridView.Models.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
<LangVersion>latest</LangVersion>
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
8+
<ItemGroup>
9+
<InternalsVisibleTo Include="Microsoft.PowerShell.ConsoleGuiTools.Tests" />
10+
</ItemGroup>
811
<ItemGroup>
912
<PackageReference Include="Newtonsoft.Json" />
1013
<PackageReference Include="System.Management.Automation" />
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
Describe 'Microsoft.PowerShell.ConsoleGuiTools Module' {
5+
6+
BeforeAll {
7+
$modulePath = Join-Path $PSScriptRoot '..' 'module' 'Microsoft.PowerShell.ConsoleGuiTools.psd1'
8+
if (-not (Test-Path $modulePath)) {
9+
$modulePath = Join-Path $PSScriptRoot '..' 'src' 'Microsoft.PowerShell.ConsoleGuiTools' 'publish' 'Microsoft.PowerShell.ConsoleGuiTools.psd1'
10+
}
11+
if (Test-Path $modulePath) {
12+
Import-Module $modulePath -Force -ErrorAction Stop
13+
} else {
14+
throw "Module not found. Build the project first with 'Invoke-Build Build'."
15+
}
16+
}
17+
18+
Context 'Module loads correctly' {
19+
It 'Should import without errors' {
20+
$module = Get-Module -Name Microsoft.PowerShell.ConsoleGuiTools
21+
$module | Should -Not -BeNullOrEmpty
22+
}
23+
24+
It 'Should export Out-ConsoleGridView command' {
25+
$cmd = Get-Command -Name Out-ConsoleGridView -Module Microsoft.PowerShell.ConsoleGuiTools -ErrorAction SilentlyContinue
26+
$cmd | Should -Not -BeNullOrEmpty
27+
}
28+
29+
It 'Should export Show-ObjectTree command' {
30+
$cmd = Get-Command -Name Show-ObjectTree -Module Microsoft.PowerShell.ConsoleGuiTools -ErrorAction SilentlyContinue
31+
$cmd | Should -Not -BeNullOrEmpty
32+
}
33+
}
34+
35+
Context 'Aliases' {
36+
It 'Should register ocgv alias for Out-ConsoleGridView' {
37+
$alias = Get-Alias -Name ocgv -ErrorAction SilentlyContinue
38+
$alias | Should -Not -BeNullOrEmpty
39+
$alias.Definition | Should -Be 'Out-ConsoleGridView'
40+
}
41+
42+
It 'Should register shot alias for Show-ObjectTree' {
43+
$alias = Get-Alias -Name shot -ErrorAction SilentlyContinue
44+
$alias | Should -Not -BeNullOrEmpty
45+
$alias.Definition | Should -Be 'Show-ObjectTree'
46+
}
47+
}
48+
49+
Context 'Out-ConsoleGridView parameters' {
50+
It 'Should have InputObject parameter' {
51+
$cmd = Get-Command Out-ConsoleGridView
52+
$cmd.Parameters.Keys | Should -Contain 'InputObject'
53+
}
54+
55+
It 'Should have Title parameter' {
56+
$cmd = Get-Command Out-ConsoleGridView
57+
$cmd.Parameters.Keys | Should -Contain 'Title'
58+
}
59+
60+
It 'Should have OutputMode parameter' {
61+
$cmd = Get-Command Out-ConsoleGridView
62+
$cmd.Parameters.Keys | Should -Contain 'OutputMode'
63+
}
64+
65+
It 'Should have Filter parameter' {
66+
$cmd = Get-Command Out-ConsoleGridView
67+
$cmd.Parameters.Keys | Should -Contain 'Filter'
68+
}
69+
70+
It 'Should have MinUI parameter' {
71+
$cmd = Get-Command Out-ConsoleGridView
72+
$cmd.Parameters.Keys | Should -Contain 'MinUI'
73+
}
74+
}
75+
76+
Context 'Show-ObjectTree parameters' {
77+
It 'Should have InputObject parameter' {
78+
$cmd = Get-Command Show-ObjectTree
79+
$cmd.Parameters.Keys | Should -Contain 'InputObject'
80+
}
81+
82+
It 'Should have Title parameter' {
83+
$cmd = Get-Command Show-ObjectTree
84+
$cmd.Parameters.Keys | Should -Contain 'Title'
85+
}
86+
87+
It 'Should have Filter parameter' {
88+
$cmd = Get-Command Show-ObjectTree
89+
$cmd.Parameters.Keys | Should -Contain 'Filter'
90+
}
91+
92+
It 'Should have MinUI parameter' {
93+
$cmd = Get-Command Show-ObjectTree
94+
$cmd.Parameters.Keys | Should -Contain 'MinUI'
95+
}
96+
}
97+
98+
AfterAll {
99+
Remove-Module -Name Microsoft.PowerShell.ConsoleGuiTools -Force -ErrorAction SilentlyContinue
100+
}
101+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Globalization;
6+
using Microsoft.PowerShell.OutGridView.Models;
7+
using Xunit;
8+
9+
namespace Microsoft.PowerShell.ConsoleGuiTools.Tests;
10+
11+
public class DataTableColumnTests
12+
{
13+
[Fact]
14+
public void FormatValue_NullValue_ReturnsEmptyString()
15+
{
16+
var column = new DataTableColumn("Test", "$_.Test");
17+
Assert.Equal(string.Empty, column.FormatValue(null));
18+
}
19+
20+
[Fact]
21+
public void FormatValue_WithFormatString_UsesFormatString()
22+
{
23+
var column = new DataTableColumn("Test", "$_.Test") { FormatString = "N2" };
24+
var result = column.FormatValue(123.456m);
25+
// Should format as decimal with 2 decimal places
26+
Assert.Contains("123", result);
27+
}
28+
29+
[Fact]
30+
public void FormatValue_NullFormatString_UsesToString()
31+
{
32+
// When FormatString is explicitly null, use plain ToString (no default formatting)
33+
var column = new DataTableColumn("Id", "$_.Id") { FormatString = null };
34+
var result = column.FormatValue(1234);
35+
// Should NOT have thousands separator — plain ToString
36+
Assert.Equal("1234", result);
37+
}
38+
39+
[Fact]
40+
public void FormatValue_EmptyFormatString_UsesDefaultTypeFormatting()
41+
{
42+
// When FormatString is empty string (not null), use type-based defaults
43+
var column = new DataTableColumn("Size", "$_.Size") { FormatString = "" };
44+
var result = column.FormatValue(1234);
45+
// int with empty FormatString should use N0 formatting (thousands separator)
46+
var expected = 1234.ToString("N0", CultureInfo.CurrentCulture);
47+
Assert.Equal(expected, result);
48+
}
49+
50+
[Fact]
51+
public void FormatValue_DateTime_WithEmptyFormatString_UsesGeneralFormat()
52+
{
53+
var column = new DataTableColumn("Date", "$_.Date") { FormatString = "" };
54+
var dt = new DateTime(2024, 6, 15, 14, 30, 0);
55+
var result = column.FormatValue(dt);
56+
var expected = dt.ToString("G", CultureInfo.CurrentCulture);
57+
Assert.Equal(expected, result);
58+
}
59+
60+
[Fact]
61+
public void FormatValue_Decimal_WithEmptyFormatString_UsesN0()
62+
{
63+
var column = new DataTableColumn("Amount", "$_.Amount") { FormatString = "" };
64+
var result = column.FormatValue(1234567.89m);
65+
var expected = 1234567.89m.ToString("N0", CultureInfo.CurrentCulture);
66+
Assert.Equal(expected, result);
67+
}
68+
69+
[Fact]
70+
public void FormatValue_Double_WithEmptyFormatString_UsesN2()
71+
{
72+
var column = new DataTableColumn("Value", "$_.Value") { FormatString = "" };
73+
var result = column.FormatValue(3.14159);
74+
var expected = 3.14159.ToString("N2", CultureInfo.CurrentCulture);
75+
Assert.Equal(expected, result);
76+
}
77+
78+
[Fact]
79+
public void FormatValue_String_ReturnsStringValue()
80+
{
81+
var column = new DataTableColumn("Name", "$_.Name");
82+
Assert.Equal("hello", column.FormatValue("hello"));
83+
}
84+
85+
[Fact]
86+
public void FormatValue_InvalidFormatString_FallsThrough()
87+
{
88+
var column = new DataTableColumn("Test", "$_.Test") { FormatString = "ZZZZ_INVALID" };
89+
// An invalid format string should not throw — it should fall through
90+
var result = column.FormatValue(42);
91+
Assert.NotNull(result);
92+
}
93+
94+
[Fact]
95+
public void Equals_SameLabelAndAccessor_ReturnsTrue()
96+
{
97+
var a = new DataTableColumn("Name", "$_.Name");
98+
var b = new DataTableColumn("Name", "$_.Name");
99+
Assert.True(a.Equals(b));
100+
}
101+
102+
[Fact]
103+
public void Equals_DifferentLabel_ReturnsFalse()
104+
{
105+
var a = new DataTableColumn("Name", "$_.Name");
106+
var b = new DataTableColumn("Id", "$_.Name");
107+
Assert.False(a.Equals(b));
108+
}
109+
110+
[Fact]
111+
public void Equals_DifferentAccessor_ReturnsFalse()
112+
{
113+
var a = new DataTableColumn("Name", "$_.Name");
114+
var b = new DataTableColumn("Name", "$_.Id");
115+
Assert.False(a.Equals(b));
116+
}
117+
118+
[Fact]
119+
public void Equals_Null_ReturnsFalse()
120+
{
121+
var a = new DataTableColumn("Name", "$_.Name");
122+
Assert.False(a.Equals(null));
123+
}
124+
125+
[Fact]
126+
public void GetHashCode_EqualColumns_SameHashCode()
127+
{
128+
var a = new DataTableColumn("Name", "$_.Name");
129+
var b = new DataTableColumn("Name", "$_.Name");
130+
Assert.Equal(a.GetHashCode(), b.GetHashCode());
131+
}
132+
133+
[Fact]
134+
public void ToString_ReturnsBase64EncodedString()
135+
{
136+
var column = new DataTableColumn("Name", "$_.Name");
137+
var result = column.ToString();
138+
// Should decode to "Name" + "$_.Name"
139+
var decoded = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(result));
140+
Assert.Equal("Name$_.Name", decoded);
141+
}
142+
143+
[Fact]
144+
public void Type_ValidStringType_ReturnsCorrectType()
145+
{
146+
var column = new DataTableColumn("Test", "$_.Test")
147+
{
148+
StringType = typeof(decimal).FullName
149+
};
150+
Assert.Equal(typeof(decimal), column.Type);
151+
}
152+
153+
[Fact]
154+
public void Type_NullStringType_ThrowsOnAccess()
155+
{
156+
var column = new DataTableColumn("Test", "$_.Test");
157+
// StringType is null by default; Type.GetType(null) throws ArgumentNullException
158+
Assert.Throws<ArgumentNullException>(() => column.Type);
159+
}
160+
}

0 commit comments

Comments
 (0)