using SharepointToolbox.Core.Models; using SharepointToolbox.Services; namespace SharepointToolbox.Tests.Services; public class BulkOperationRunnerTests { [Fact] public async Task RunAsync_AllSucceed_ReturnsAllSuccess() { var items = new List { "a", "b", "c" }; var progress = new Progress(); var summary = await BulkOperationRunner.RunAsync( items, (item, idx, ct) => Task.CompletedTask, progress, CancellationToken.None); Assert.Equal(3, summary.TotalCount); Assert.Equal(3, summary.SuccessCount); Assert.Equal(0, summary.FailedCount); Assert.False(summary.HasFailures); } [Fact] public async Task RunAsync_SomeItemsFail_ContinuesAndReportsPerItem() { var items = new List { "ok1", "fail", "ok2" }; var progress = new Progress(); var summary = await BulkOperationRunner.RunAsync( items, (item, idx, ct) => { if (item == "fail") throw new InvalidOperationException("Test error"); return Task.CompletedTask; }, progress, CancellationToken.None); Assert.Equal(3, summary.TotalCount); Assert.Equal(2, summary.SuccessCount); Assert.Equal(1, summary.FailedCount); Assert.True(summary.HasFailures); Assert.Contains(summary.FailedItems, r => r.ErrorMessage == "Test error"); } [Fact] public async Task RunAsync_Cancelled_ThrowsOperationCanceled() { var items = new List { "a", "b", "c" }; var cts = new CancellationTokenSource(); cts.Cancel(); var progress = new Progress(); await Assert.ThrowsAsync(() => BulkOperationRunner.RunAsync( items, (item, idx, ct) => Task.CompletedTask, progress, cts.Token)); } [Fact] public async Task RunAsync_CancelledMidOperation_StopsProcessing() { var items = new List { "a", "b", "c", "d" }; var cts = new CancellationTokenSource(); var processedCount = 0; var progress = new Progress(); await Assert.ThrowsAsync(() => BulkOperationRunner.RunAsync( items, async (item, idx, ct) => { Interlocked.Increment(ref processedCount); if (idx == 1) cts.Cancel(); // cancel after second item await Task.CompletedTask; }, progress, cts.Token)); Assert.True(processedCount <= 3); // should not process all 4 } [Fact] public async Task RunAsync_ReportsProgress() { var items = new List { "a", "b" }; var progressReports = new List(); var progress = new Progress(p => progressReports.Add(p)); await BulkOperationRunner.RunAsync( items, (item, idx, ct) => Task.CompletedTask, progress, CancellationToken.None); // Progress is async, give it a moment to flush await Task.Delay(100); Assert.True(progressReports.Count >= 2); } }