using System; using System.IO; using Microsoft.Data.Sqlite; using Xunit; using ytLive.Services; using ytLive.ViewModels; namespace ytLive.Tests; /// /// Sync offsets ship at zero. A correction belongs to one camera on one desk, so a fresh profile must /// not arrive with audio already shifted — a non-zero default would move every creator's voice to fix /// one machine and would hide whether the fault is theirs or ours. /// // The view model below touches the static LayoutPathOverride, so it shares the layout collection. [Collection("MainViewModelLayoutPath")] public sealed class AudioSyncSettingsTests : IDisposable { private readonly string _db = Path.Combine(Path.GetTempPath(), $"ytLlive-syncsettings-{Guid.NewGuid():N}.db"); public void Dispose() { SqliteConnection.ClearAllPools(); try { File.Delete(_db); } catch (IOException) { /* best effort */ } } [Fact] public void Both_offsets_start_at_zero_and_only_then_take_a_value() { using (var store = new LayoutStore(_db)) { Assert.Equal(0, store.LoadMicSyncOffsetMs()); // opt-in, not pre-applied Assert.Equal(0, store.LoadAudioSyncOffsetMs()); // A mic delay cannot be negative — advancing is the global offset's job. store.SaveMicSyncOffsetMs(-120); Assert.Equal(0, store.LoadMicSyncOffsetMs()); store.SaveMicSyncOffsetMs(600); // beyond the slider's range Assert.Equal(500, store.LoadMicSyncOffsetMs()); store.SaveMicSyncOffsetMs(240); store.SaveAudioSyncOffsetMs(-130); } using var reopened = new LayoutStore(_db); Assert.Equal(240, reopened.LoadMicSyncOffsetMs()); Assert.Equal(-130, reopened.LoadAudioSyncOffsetMs()); } /// /// A slider move is persisted as it happens. It used to ride the debounced layout save, so a value /// set seconds before closing the app was lost — which cost a record-and-measure cycle on 2026-11-12 /// when a −130 ms offset vanished between two clips. /// [Fact] public void A_slider_move_survives_without_any_debounce_flush() { MainViewModel.LayoutPathOverride = _db; try { var vm = new MainViewModel(); vm.AudioSyncOffsetMs = -130; vm.MicSyncOffsetMs = 240; using var store = new LayoutStore(_db); Assert.Equal(-130, store.LoadAudioSyncOffsetMs()); Assert.Equal(240, store.LoadMicSyncOffsetMs()); } finally { MainViewModel.LayoutPathOverride = null; } } }