using ClaudeDo.Ui.ViewModels.Modals; namespace ClaudeDo.Ui.Tests.ViewModels; public class WeeklyReportModalViewModelTests { private sealed class Worker : StubWorkerClient { public TaskCompletionSource Gate { get; } = new(); public bool Throw { get; set; } public override Task GenerateWeekReportAsync(DateOnly start, DateOnly end) => Throw ? Task.FromException(new InvalidOperationException("boom")) : Gate.Task; } private static WeeklyReportModalViewModel Build(Worker worker) { var vm = new WeeklyReportModalViewModel(worker) { StartDate = new DateTime(2026, 6, 1), EndDate = new DateTime(2026, 6, 3), }; return vm; } [Fact] public async Task Generate_sets_IsRunning_while_pending_and_clears_it_after() { var worker = new Worker(); var vm = Build(worker); var generate = vm.GenerateCommand.ExecuteAsync(null); Assert.True(vm.GenerateOperation.IsRunning); worker.Gate.SetResult("# report"); await generate; Assert.False(vm.GenerateOperation.IsRunning); Assert.Equal("# report", vm.ReportMarkdown); } [Fact] public async Task GenerateCommand_CanExecute_is_locked_while_running() { var worker = new Worker(); var vm = Build(worker); var generate = vm.GenerateCommand.ExecuteAsync(null); Assert.False(vm.GenerateCommand.CanExecute(null)); worker.Gate.SetResult("# report"); await generate; Assert.True(vm.GenerateCommand.CanExecute(null)); } [Fact] public async Task Generate_ends_the_operation_when_the_worker_call_throws() { var worker = new Worker { Throw = true }; var vm = Build(worker); await vm.GenerateCommand.ExecuteAsync(null); Assert.False(vm.GenerateOperation.IsRunning); Assert.True(vm.GenerateCommand.CanExecute(null)); Assert.False(string.IsNullOrWhiteSpace(vm.StatusMessage)); } }