104 lines
4.1 KiB
C#
104 lines
4.1 KiB
C#
using ClaudeDo.Localization;
|
|
using ClaudeDo.Ui;
|
|
using ClaudeDo.Ui.Services;
|
|
using ClaudeDo.Ui.ViewModels.Modals;
|
|
using ClaudeDo.Ui.ViewModels.Modals.Settings;
|
|
using Xunit;
|
|
|
|
namespace ClaudeDo.Ui.Tests.ViewModels;
|
|
|
|
public class SettingsModalViewModelTests
|
|
{
|
|
private sealed class FakeWorker : StubWorkerClient
|
|
{
|
|
public AppSettingsDto? AppToReturn;
|
|
public AppSettingsDto? Saved;
|
|
public override Task<AppSettingsDto?> GetAppSettingsAsync() => Task.FromResult(AppToReturn);
|
|
public override Task UpdateAppSettingsAsync(AppSettingsDto dto) { Saved = dto; return Task.CompletedTask; }
|
|
}
|
|
|
|
private sealed class FakePrimeApi : IPrimeScheduleApi
|
|
{
|
|
public Task<List<PrimeScheduleDto>> ListAsync() => Task.FromResult(new List<PrimeScheduleDto>());
|
|
public Task<PrimeScheduleDto?> UpsertAsync(PrimeScheduleDto dto) => Task.FromResult<PrimeScheduleDto?>(dto);
|
|
public Task DeleteAsync(Guid id) => Task.CompletedTask;
|
|
}
|
|
|
|
private static Localizer MakeLocalizer()
|
|
{
|
|
var dir = Path.Combine(Path.GetTempPath(), "loc_" + Guid.NewGuid().ToString("N"));
|
|
Directory.CreateDirectory(dir);
|
|
File.WriteAllText(Path.Combine(dir, "en.json"),
|
|
"""{ "metadata": { "code": "en", "name": "English" }, "settings": { "save": "Save" } }""");
|
|
File.WriteAllText(Path.Combine(dir, "de.json"),
|
|
"""{ "metadata": { "code": "de", "name": "Deutsch" }, "settings": { "save": "Speichern" } }""");
|
|
return new Localizer(LocaleStore.Load(dir), "en");
|
|
}
|
|
|
|
private static AppSettingsDto DtoWith(int fiveHourPct, int sevenDayPct) =>
|
|
new(DefaultClaudeInstructions: "", DefaultModel: "sonnet", DefaultMaxTurns: 30,
|
|
DefaultPermissionMode: "auto", MaxParallelExecutions: 1, WorktreeStrategy: "sibling",
|
|
CentralWorktreeRoot: null, WorktreeAutoCleanupEnabled: false, WorktreeAutoCleanupDays: 7,
|
|
ReportExcludedPaths: null, StandupWeekday: 3, DailyPrepMaxTasks: 5,
|
|
SessionSkills: null, ModelPresets: null,
|
|
UsageGateFiveHourPct: fiveHourPct, UsageGateSevenDayPct: sevenDayPct);
|
|
|
|
[Fact]
|
|
public async Task Save_carries_dragged_throttle_stages_through_untouched()
|
|
{
|
|
// The throttle stages are only editable by dragging the usage-monitor gauges. Saving the
|
|
// Settings modal rebuilds the whole DTO, so it must not reset them to the defaults.
|
|
var worker = new FakeWorker
|
|
{
|
|
AppToReturn = DtoWith(65, 95) with
|
|
{
|
|
UsageThrottleFiveHourSoftPct = 42,
|
|
UsageThrottleFiveHourHardPct = 58,
|
|
UsageThrottleSevenDaySoftPct = 71,
|
|
UsageThrottleSevenDayHardPct = 88,
|
|
},
|
|
};
|
|
var vm = MakeVm(worker);
|
|
await vm.LoadAsync();
|
|
|
|
await vm.SaveCommand.ExecuteAsync(null);
|
|
|
|
Assert.NotNull(worker.Saved);
|
|
Assert.Equal(42, worker.Saved!.UsageThrottleFiveHourSoftPct);
|
|
Assert.Equal(58, worker.Saved.UsageThrottleFiveHourHardPct);
|
|
Assert.Equal(71, worker.Saved.UsageThrottleSevenDaySoftPct);
|
|
Assert.Equal(88, worker.Saved.UsageThrottleSevenDayHardPct);
|
|
}
|
|
|
|
private static SettingsModalViewModel MakeVm(FakeWorker worker) =>
|
|
new(worker, new PrimeClaudeTabViewModel(new FakePrimeApi()), new OnlineLoginService(),
|
|
MakeLocalizer(), new AppSettings());
|
|
|
|
[Fact]
|
|
public async Task LoadAsync_fills_usage_gate_fields_from_dto()
|
|
{
|
|
var worker = new FakeWorker { AppToReturn = DtoWith(65, 95) };
|
|
var vm = MakeVm(worker);
|
|
|
|
await vm.LoadAsync();
|
|
|
|
Assert.Equal(65, vm.General.UsageGateFiveHourPct);
|
|
Assert.Equal(95, vm.General.UsageGateSevenDayPct);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Save_sends_usage_gate_fields_in_dto()
|
|
{
|
|
var worker = new FakeWorker();
|
|
var vm = MakeVm(worker);
|
|
vm.General.UsageGateFiveHourPct = 42;
|
|
vm.General.UsageGateSevenDayPct = 77;
|
|
|
|
await vm.SaveCommand.ExecuteAsync(null);
|
|
|
|
Assert.NotNull(worker.Saved);
|
|
Assert.Equal(42, worker.Saved!.UsageGateFiveHourPct);
|
|
Assert.Equal(77, worker.Saved.UsageGateSevenDayPct);
|
|
}
|
|
}
|