using ClaudeDo.Data; using ClaudeDo.Localization; using ClaudeDo.Ui.Localization; using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels; using ClaudeDo.Ui.ViewModels.Conflicts; using ClaudeDo.Ui.ViewModels.Islands; using ClaudeDo.Ui.ViewModels.Modals; using Microsoft.EntityFrameworkCore; namespace ClaudeDo.Ui.Tests.ViewModels; // "New list" pre-creates the DB row and then opens List Settings on it. Cancelling (or closing) // that modal used to leave an untitled empty list behind — CreateListAsync rolls the row back // unless the modal reports Saved (or Deleted, which already handled itself). public class ListsIslandCreateListCancelTests : IDisposable { private readonly string _dbPath; public ListsIslandCreateListCancelTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_newlist_cancel_{Guid.NewGuid():N}.db"); using var ctx = NewContext(); ctx.Database.EnsureCreated(); var dir = AppContext.BaseDirectory; while (dir is not null && !Directory.Exists(Path.Combine(dir, "src", "ClaudeDo.Localization", "locales"))) dir = Path.GetDirectoryName(dir); Loc.Current = new Localizer( LocaleStore.Load(Path.Combine(dir!, "src", "ClaudeDo.Localization", "locales")), "en"); } public void Dispose() { try { File.Delete(_dbPath); } catch { } try { File.Delete(_dbPath + "-wal"); } catch { } try { File.Delete(_dbPath + "-shm"); } catch { } } private ClaudeDoDbContext NewContext() { var opts = new DbContextOptionsBuilder() .UseSqlite($"Data Source={_dbPath}") .Options; return new ClaudeDoDbContext(opts); } // Stands in for the modal window: either leaves the VM untouched (cancel / window close) // or runs its Save command. private sealed class FakeDialogService(bool save) : IDialogService { public Task ShowListSettingsAsync(ListSettingsModalViewModel vm) => save ? vm.SaveCommand.ExecuteAsync(null) : Task.CompletedTask; public Task ShowAboutAsync(AboutModalViewModel vm) => throw new NotImplementedException(); public Task ShowWeeklyReportAsync(WeeklyReportModalViewModel vm) => throw new NotImplementedException(); public Task ShowUsageMonitorAsync(UsageMonitorModalViewModel vm) => throw new NotImplementedException(); public Task ShowSettingsAsync(SettingsModalViewModel vm) => throw new NotImplementedException(); public Task ShowRepoImportAsync(RepoImportModalViewModel vm) => throw new NotImplementedException(); public Task ShowWorktreesOverviewAsync(WorktreesOverviewModalViewModel vm) => throw new NotImplementedException(); public Task?> ShowMergeHelperSelectionAsync(MergeHelperSelectionModalViewModel vm) => throw new NotImplementedException(); public Task ShowWorkerConnectionAsync(WorkerConnectionModalViewModel vm) => throw new NotImplementedException(); public Task ShowConflictResolverAsync(ConflictResolverViewModel vm) => throw new NotImplementedException(); public Task ShowLogVisualizerAsync(LogVisualizerViewModel vm) => throw new NotImplementedException(); public Task ConfirmAsync(string message) => Task.FromResult(true); public Task ShowErrorAsync(string message) => Task.CompletedTask; public void ShowMissionControl(MissionControlViewModel vm) => throw new NotImplementedException(); public void ShowCheatSheets(CheatSheetsViewModel vm) => throw new NotImplementedException(); } private sealed class ListSettingsProvider(Func create) : IServiceProvider { public object? GetService(Type serviceType) => serviceType == typeof(ListSettingsModalViewModel) ? create() : null; } private async Task RunCreateListAsync(bool save) { var factory = new TestDbFactory(NewContext); var worker = new DefaultStub(); var services = new ListSettingsProvider(() => new ListSettingsModalViewModel(worker, factory)); var vm = new ListsIslandViewModel(factory, services) { Dialogs = new FakeDialogService(save) }; await vm.LoadAsync(); await vm.CreateListCommand.ExecuteAsync(null); return vm; } [Fact] public async Task CancellingListSettings_RemovesThePreCreatedList() { var vm = await RunCreateListAsync(save: false); await using var db = NewContext(); Assert.Empty(db.Lists); Assert.Empty(vm.UserLists); } [Fact] public async Task SavingListSettings_KeepsTheNewList() { var vm = await RunCreateListAsync(save: true); await using var db = NewContext(); Assert.Single(db.Lists); Assert.Single(vm.UserLists); } }