Wave 1: LiveCharts2 NuGet + FileTypeMetric model + IStorageService extension Wave 2: StorageService file-type enumeration implementation Wave 3: ViewModel chart properties + View XAML + localization Wave 4: Unit tests for chart ViewModel behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
196 lines
8.9 KiB
Markdown
196 lines
8.9 KiB
Markdown
---
|
|
phase: 09-storage-visualization
|
|
plan: 04
|
|
type: execute
|
|
wave: 4
|
|
depends_on:
|
|
- "09-03"
|
|
files_modified:
|
|
- SharepointToolbox.Tests/ViewModels/StorageViewModelChartTests.cs
|
|
autonomous: true
|
|
requirements:
|
|
- VIZZ-01
|
|
- VIZZ-02
|
|
- VIZZ-03
|
|
must_haves:
|
|
truths:
|
|
- "Unit tests verify chart series are computed from FileTypeMetric data"
|
|
- "Unit tests verify donut/bar toggle changes series without re-scanning"
|
|
- "Unit tests verify top-10 + Other aggregation logic"
|
|
- "Unit tests verify chart data clears on tenant switch"
|
|
artifacts:
|
|
- path: "SharepointToolbox.Tests/ViewModels/StorageViewModelChartTests.cs"
|
|
provides: "Chart-specific unit tests for StorageViewModel"
|
|
contains: "class StorageViewModelChartTests"
|
|
key_links:
|
|
- from: "SharepointToolbox.Tests/ViewModels/StorageViewModelChartTests.cs"
|
|
to: "SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs"
|
|
via: "Tests chart properties and UpdateChartSeries behavior"
|
|
pattern: "StorageViewModel"
|
|
---
|
|
|
|
<objective>
|
|
Create unit tests for StorageViewModel chart functionality: FileTypeMetric aggregation into chart series, donut/bar toggle behavior, top-10 + Other logic, and tenant switch cleanup.
|
|
|
|
Purpose: Validates VIZZ-01 (charting library integration via series creation), VIZZ-02 (chart data from file types), and VIZZ-03 (toggle behavior) at the ViewModel level without requiring a live SharePoint connection.
|
|
Output: StorageViewModelChartTests.cs
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md
|
|
@C:/Users/dev/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/09-storage-visualization/09-01-SUMMARY.md
|
|
@.planning/phases/09-storage-visualization/09-02-SUMMARY.md
|
|
@.planning/phases/09-storage-visualization/09-03-SUMMARY.md
|
|
|
|
<interfaces>
|
|
<!-- From Plan 09-03: StorageViewModel chart properties -->
|
|
From SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs (chart additions):
|
|
```csharp
|
|
// New observable properties:
|
|
[ObservableProperty] private bool _isDonutChart = true;
|
|
public ObservableCollection<FileTypeMetric> FileTypeMetrics { get; private set; }
|
|
public bool HasChartData => FileTypeMetrics.Count > 0;
|
|
public IEnumerable<ISeries> PieChartSeries { get; private set; }
|
|
public IEnumerable<ISeries> BarChartSeries { get; private set; }
|
|
public Axis[] BarXAxes { get; private set; }
|
|
public Axis[] BarYAxes { get; private set; }
|
|
|
|
// Existing test constructor:
|
|
internal StorageViewModel(IStorageService, ISessionManager, ILogger<FeatureViewModelBase>)
|
|
|
|
// Existing test helper:
|
|
internal Task TestRunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
|
|
|
|
// Existing setup helper:
|
|
internal void SetCurrentProfile(TenantProfile profile)
|
|
```
|
|
|
|
From SharepointToolbox/Core/Models/FileTypeMetric.cs:
|
|
```csharp
|
|
public record FileTypeMetric(string Extension, long TotalSizeBytes, int FileCount)
|
|
{
|
|
public string DisplayLabel => ...;
|
|
}
|
|
```
|
|
|
|
From SharepointToolbox/Services/IStorageService.cs:
|
|
```csharp
|
|
public interface IStorageService
|
|
{
|
|
Task<IReadOnlyList<StorageNode>> CollectStorageAsync(...);
|
|
Task<IReadOnlyList<FileTypeMetric>> CollectFileTypeMetricsAsync(
|
|
ClientContext ctx, IProgress<OperationProgress> progress, CancellationToken ct);
|
|
}
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Create StorageViewModel chart unit tests</name>
|
|
<files>SharepointToolbox.Tests/ViewModels/StorageViewModelChartTests.cs</files>
|
|
<behavior>
|
|
- Test 1: After RunOperationAsync with mock returning FileTypeMetrics, HasChartData is true and PieChartSeries has entries
|
|
- Test 2: After RunOperationAsync, BarChartSeries has exactly 1 ColumnSeries with values matching metric count
|
|
- Test 3: Toggle IsDonutChart from true to false updates PieChartSeries (InnerRadius changes) without calling service again
|
|
- Test 4: When mock returns >10 file types, chart series has 11 entries (10 + Other)
|
|
- Test 5: When mock returns <=10 file types, no "Other" entry is added
|
|
- Test 6: OnTenantSwitched clears FileTypeMetrics and HasChartData becomes false
|
|
- Test 7: When mock returns empty file type list, HasChartData is false and series are empty
|
|
</behavior>
|
|
<action>
|
|
Create `SharepointToolbox.Tests/ViewModels/StorageViewModelChartTests.cs`.
|
|
|
|
First, check the existing test project structure for patterns:
|
|
```bash
|
|
ls SharepointToolbox.Tests/ViewModels/
|
|
```
|
|
and read an existing ViewModel test to understand mock patterns (likely uses Moq or NSubstitute).
|
|
|
|
Also check the test project csproj for testing frameworks:
|
|
```bash
|
|
cat SharepointToolbox.Tests/SharepointToolbox.Tests.csproj
|
|
```
|
|
|
|
Create the test file following existing patterns. The tests should:
|
|
|
|
1. Use the internal test constructor: `new StorageViewModel(mockStorageService, mockSessionManager, mockLogger)`
|
|
2. Mock `IStorageService` to return predetermined `FileTypeMetric` lists from `CollectFileTypeMetricsAsync`
|
|
3. Mock `IStorageService.CollectStorageAsync` to return empty list (we only care about chart data)
|
|
4. Mock `ISessionManager.GetOrCreateContextAsync` -- this is tricky since it returns `ClientContext` which is hard to mock. Follow existing test patterns. If existing tests use reflection or a different approach, follow that.
|
|
5. Call `vm.SetCurrentProfile(new TenantProfile { TenantUrl = "https://test.sharepoint.com", ClientId = "test", Name = "Test" })`
|
|
6. Set `vm.SiteUrl = "https://test.sharepoint.com/sites/test"`
|
|
7. Call `await vm.TestRunOperationAsync(CancellationToken.None, new Progress<OperationProgress>(_ => {}))`
|
|
8. Assert chart properties
|
|
|
|
**Test structure:**
|
|
|
|
```csharp
|
|
using System.Collections.ObjectModel;
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
using LiveChartsCore;
|
|
using LiveChartsCore.SkiaSharpView;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Moq; // or NSubstitute -- check existing test patterns
|
|
using SharepointToolbox.Core.Models;
|
|
using SharepointToolbox.Services;
|
|
using SharepointToolbox.ViewModels.Tabs;
|
|
|
|
namespace SharepointToolbox.Tests.ViewModels;
|
|
|
|
public class StorageViewModelChartTests
|
|
{
|
|
// Helper to create ViewModel with mocked services
|
|
// Helper to create sample FileTypeMetric lists
|
|
// 7 test methods as described in behavior block
|
|
}
|
|
```
|
|
|
|
**Critical note on ClientContext mocking:** ClientContext is a sealed CSOM class that cannot be directly mocked with Moq. Check how existing StorageService tests or StorageViewModel tests handle this. If there are no existing ViewModel tests that call TestRunOperationAsync (check existing test files), you may need to:
|
|
- Skip the full RunOperationAsync flow and instead directly set FileTypeMetrics via reflection
|
|
- OR mock ISessionManager to return null/throw and test a different path
|
|
- OR create tests that only verify the UpdateChartSeries logic by setting FileTypeMetrics directly
|
|
|
|
The SAFEST approach if ClientContext cannot be mocked: Make `UpdateChartSeries` and `FileTypeMetrics` setter accessible for testing. Since FileTypeMetrics has a private setter, you can set it via reflection in tests:
|
|
```csharp
|
|
var metricsProperty = typeof(StorageViewModel).GetProperty("FileTypeMetrics");
|
|
metricsProperty!.SetValue(vm, new ObservableCollection<FileTypeMetric>(testMetrics));
|
|
```
|
|
|
|
This tests the chart logic without needing a real SharePoint connection.
|
|
|
|
**Alternative approach:** If the project already has patterns for testing RunOperationAsync (check Phase 7 UserAccessAuditViewModel tests for TestRunOperationAsync usage), follow that pattern exactly.
|
|
|
|
Remember to add `WeakReferenceMessenger.Default.Reset()` in test constructor to prevent cross-test contamination (Phase 7 convention).
|
|
</action>
|
|
<verify>
|
|
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --filter "FullyQualifiedName~StorageViewModelChartTests" --no-build 2>&1 | tail -15</automated>
|
|
</verify>
|
|
<done>StorageViewModelChartTests.cs has 7 passing tests covering: chart series from metrics, bar series structure, toggle behavior, top-10+Other aggregation, no-Other for <=10 items, tenant switch cleanup, empty data handling. All tests pass. No existing tests are broken.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `dotnet test SharepointToolbox.Tests/ --filter "StorageViewModelChartTests"` -- all tests pass
|
|
- `dotnet test SharepointToolbox.Tests/` -- all existing tests still pass (no regressions)
|
|
- Tests cover all 3 VIZZ requirements at the ViewModel level
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
All 7 chart-related unit tests pass. No regression in existing test suite. Tests verify chart data computation, toggle behavior, aggregation logic, and cleanup -- all without requiring a live SharePoint connection.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/09-storage-visualization/09-04-SUMMARY.md`
|
|
</output>
|