From 39527814d6b98ecff1ee71a84cd9a4a242dd6117 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 12 Jun 2026 10:16:23 -0400 Subject: [PATCH 1/3] Update copilot instructions and add SpokesLength property to Chart class --- .github/copilot-instructions.md | 28 ++++++++++++++++++++++++---- Sources/Chart.cs | 1 + 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2d86f45..e414f67 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -5,16 +5,18 @@ This project is a **hybrid C# + PowerShell module**. The C# layer compiles into platform-specific DLLs; the PowerShell layer loads the right DLL at import time and exposes cmdlets. ``` -Sources/ ← C# library (ScottPlot + SkiaSharp, netstandard2.0) +Sources/ ← C# library (ScottPlot + SkiaSharp, net8.0 / netstandard2.0) Chart.cs ← Static base class; all chart settings live here as static props - PieChart.cs / BarChart.cs / StackedBarChart.cs / SignalChart.cs ← Chart implementations + PieChart.cs / DonutChart.cs / BarChart.cs / StackedBarChart.cs / SignalChart.cs / RadarChart.cs + ← Chart implementations PowerShell/ ← One PSCmdlet class per chart type (New-*Chart cmdlets) Enums/Enums.cs ← All shared enums (BasicColors, Formats, ColorPalettes, etc.) AsBuiltReport.Chart/ ← PowerShell module AsBuiltReport.Chart.psm1 ← Loads the correct DLL based on PSEdition + OS + architecture - AsBuiltReport.Chart.psd1 ← Module manifest; exports: New-PieChart, New-BarChart, - New-StackedBarChart, New-SingleStackedBarChart, New-SignalChart + AsBuiltReport.Chart.psd1 ← Module manifest; exports: New-PieChart, New-DonutChart, + New-BarChart, New-StackedBarChart, New-SingleStackedBarChart, + New-SignalChart, New-RadarChart Src/Assemblies/ ← Pre-compiled DLLs, organized by platform: Core/linux-x64/ Core/windows-x64/ @@ -70,8 +72,26 @@ Invoke-ScriptAnalyzer -Path . -Recurse -Settings .\.github\workflows\PSScriptAna Excluded rules: `PSUseToExportFieldsInManifest`, `PSReviewUnusedParameter`, `PSUseDeclaredVarsMoreThanAssignments`, `PSAvoidGlobalVars`. +### Build (Pester Tests) in CI/CD + +```powershell +.\Tests\Invoke-Tests.ps1 -CodeCoverage -OutputFormat NUnitXml +``` + +Supports optional flags: +- `-CodeCoverage` – Enable code coverage analysis +- `-OutputFormat ` – Output format for test results (default: Console) + ## Key Conventions +### Cross-platform DLL loading + +The `.psm1` module import process detects the current PowerShell edition, OS, and architecture, then loads the appropriate pre-compiled DLL: +- **PowerShell 7+** on Windows/Linux/macOS → Loads from `Core/` folder +- **PowerShell 5.1 (Desktop)** on Windows → Loads from `Desktop/windows-x64/` folder (Windows-only) + +If the correct DLL cannot be found for the runtime, the module import fails with a clear error message. + ### Adding a new chart type Every new chart type requires changes in both layers: diff --git a/Sources/Chart.cs b/Sources/Chart.cs index fc574c4..318caa5 100644 --- a/Sources/Chart.cs +++ b/Sources/Chart.cs @@ -483,6 +483,7 @@ internal static void Reset() _watermarkOpacity = 0.3; DonutFraction = 0.5; HideValues = false; + SpokesLength = 10; } public static string GenerateToken(Byte length) From 5c56c3b454caa85f20ba1e23d2dcdda40431997f Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 12 Jun 2026 11:15:32 -0400 Subject: [PATCH 2/3] Add tests for New-RadarChart functionality and export verification --- Tests/AsBuiltReport.Chart.Functions.Tests.ps1 | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/Tests/AsBuiltReport.Chart.Functions.Tests.ps1 b/Tests/AsBuiltReport.Chart.Functions.Tests.ps1 index faba0c6..3264829 100644 --- a/Tests/AsBuiltReport.Chart.Functions.Tests.ps1 +++ b/Tests/AsBuiltReport.Chart.Functions.Tests.ps1 @@ -23,6 +23,12 @@ Describe 'AsBuiltReport.Chart Exported Functions' { It 'Should export New-SingleStackedBarChart' { Get-Command -Module AsBuiltReport.Chart -Name New-SingleStackedBarChart | Should -Not -BeNullOrEmpty } + It 'Should export New-DonutChart' { + Get-Command -Module AsBuiltReport.Chart -Name New-DonutChart | Should -Not -BeNullOrEmpty + } + It 'Should export New-RadarChart' { + Get-Command -Module AsBuiltReport.Chart -Name New-RadarChart | Should -Not -BeNullOrEmpty + } Context 'New-PieChart' { It 'Should run without error with sample input' { @@ -234,6 +240,62 @@ Describe 'AsBuiltReport.Chart Exported Functions' { } } + Context 'New-RadarChart' { + It 'Should run without error with sample input' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw + } + It 'Should return a file path as output' { + $result = New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive + $result | Should -BeOfType 'System.IO.FileSystemInfo' + Test-Path $result | Should -BeTrue + } + It 'Should throw error for missing mandatory parameters' { + { New-RadarChart } | Should -Throw + } + It 'Should throw error for missing Title' { + { New-RadarChart -Values @(@(1, 2, 5, 8)) -LegendLabels @('A') -Format 'png' -OutputFolderPath $TestDrive } | Should -Throw + } + It 'Should throw error for missing Values' { + { New-RadarChart -Title 'Test' -LegendLabels @('A') -Format 'png' -OutputFolderPath $TestDrive } | Should -Throw + } + It 'Should throw error for missing LegendLabels' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8)) -Format 'png' -OutputFolderPath $TestDrive } | Should -Throw + } + It 'Should throw error for mismatched Values and LegendLabels' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A') -Format 'png' -OutputFolderPath $TestDrive } | Should -Throw -ExpectedMessage "Error: Values and labels must be equal." + } + It 'Should throw error for mismatched Values elements and SpokeLabels' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive } | Should -Throw -ExpectedMessage "Every collection in the series must have the same number of items" + } + It 'Should run without error with legend enabled' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableLegend } | Should -Not -Throw + } + It 'Should run without error with legend positioned horizontally' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableLegend -LegendOrientation Horizontal -LegendAlignment UpperCenter } | Should -Not -Throw + } + It 'Should run without error with chart border enabled' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableChartBorder } | Should -Not -Throw + } + It 'Should run without error with custom color palette' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableCustomColorPalette -CustomColorPalette @('#4472C4', '#ED7D31') } | Should -Not -Throw + } + It 'Should run without error with bold title' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -TitleFontBold } | Should -Not -Throw + } + It 'Should run without error with custom title font size' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -TitleFontSize 20 } | Should -Not -Throw + } + It 'Should run without error with custom label font size' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -LabelFontSize 12 } | Should -Not -Throw + } + It 'Should run without error with custom filename' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Filename 'MyRadarChart' -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw + } + It 'Should run without error without SpokeLabels' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw + } + } + Context 'Watermark support' { Context 'New-PieChart with watermark' { It 'Should run without error with watermark enabled using defaults' { @@ -308,6 +370,23 @@ Describe 'AsBuiltReport.Chart Exported Functions' { { New-SignalChart -Title 'Test' -Values @(, [double[]]@(1, 2, 3, 4)) -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw } } + + Context 'New-RadarChart with watermark' { + It 'Should run without error with watermark enabled using defaults' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableWatermark } | Should -Not -Throw + } + It 'Should return a file when watermark is enabled' { + $result = New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableWatermark + $result | Should -BeOfType 'System.IO.FileSystemInfo' + Test-Path $result | Should -BeTrue + } + It 'Should run without error with custom watermark text, color, and opacity' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableWatermark -WatermarkText 'DRAFT' -WatermarkColor Blue -WatermarkOpacity 0.25 } | Should -Not -Throw + } + It 'Should run without error without watermark (disabled by default)' { + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw + } + } } Context 'Output format file extensions' { @@ -331,6 +410,16 @@ Describe 'AsBuiltReport.Chart Exported Functions' { $result.Extension | Should -Be '.jpeg' Test-Path $result | Should -BeTrue } + It 'New-RadarChart with Format jpg should produce a .jpg file' { + $result = New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'jpg' -OutputFolderPath $TestDrive + $result.Extension | Should -Be '.jpg' + Test-Path $result | Should -BeTrue + } + It 'New-RadarChart with Format jpeg should produce a .jpeg file' { + $result = New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'jpeg' -OutputFolderPath $TestDrive + $result.Extension | Should -Be '.jpeg' + Test-Path $result | Should -BeTrue + } } Context 'State isolation between cmdlet calls' { @@ -352,5 +441,9 @@ Describe 'AsBuiltReport.Chart Exported Functions' { New-SignalChart -Title 'Test' -Values @(, [double[]]@(1, 2, 3)) -Format 'png' -OutputFolderPath $TestDrive -EnableWatermark | Out-Null { New-SignalChart -Title 'Test' -Values @(, [double[]]@(1, 2, 3)) -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw } + It 'EnableLegend should not persist from one New-RadarChart call to the next' { + New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive -EnableLegend | Out-Null + { New-RadarChart -Title 'Test' -Values @(@(1, 2, 5, 8), @(3, 5, 4, 2)) -LegendLabels @('A', 'B') -SpokeLabels @('Wins', 'Poles', 'Podiums', 'Points') -Format 'png' -OutputFolderPath $TestDrive } | Should -Not -Throw + } } } From b783bbb177c6bb4bd0d165178042fd0336b5e6b3 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 12 Jun 2026 12:16:20 -0400 Subject: [PATCH 3/3] Update changelog for version 0.3.3 release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc64ce7..9caa7b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.3] - Unreleased +## [0.3.3] - 2026-06-12 ### Added