using System; using System.IO; using System.Linq; using Microsoft.Data.Sqlite; using Xunit; using ytLive.ViewModels; namespace ytLive.Tests; /// /// Scene-strip ordering vs F-keys (creator's report 2026-10-10). The five /// canonical scenes are loaded ORDER BY SortOrder, and a session can /// persist Chat before BRB, so the thumbnail strip renders in the wrong order /// while each tab's F-key label is name-derived — "the ordering of the 5 /// screens and their corresponding F-key is out of sequence". Fix: the VM /// reorders Scenes to the canonical F1-F5 order (Starting, Live, BRB, Chat, /// Ending) at load; the next save re-stamps SortOrder to the corrected order. /// [Collection("RealApp")] public sealed class SceneOrderTests { private readonly RealAppHost _app; public SceneOrderTests(RealAppHost app) => _app = app; [Fact] public void Scenes_Load_Into_Canonical_FKey_Order_Whatever_The_SortOrder_Rows() { _app.Run(() => { using var layout = new TempSwappedOrderLayout(); var vm = new MainViewModel(); var names = vm.Scenes.Select(s => s.Name).ToArray(); Assert.Equal(new[] { "Starting", "Live", "BRB", "Chat", "Ending" }, names); var keys = vm.Scenes.Select(s => s.HotkeyLabel).ToArray(); Assert.Equal(new[] { "F1", "F2", "F3", "F4", "F5" }, keys); // The heal persists: a save re-stamps SortOrder, so a fresh load (the // thumbnail strip's rendering source) keeps the canonical order. vm.SaveLayoutNow(); using var reloaded = new Services.LayoutStore(layout.DbPath); Assert.Equal(new[] { "Starting", "Live", "BRB", "Chat", "Ending" }, reloaded.Load().Select(s => s.Name).ToArray()); }); } /// Creates a DB whose five scenes are persisted with Chat BEFORE /// BRB — the exact stale state found on the creator's box. private sealed class TempSwappedOrderLayout : IDisposable { public string DbPath { get; } private readonly string _path; public TempSwappedOrderLayout() { _path = Path.Combine(Path.GetTempPath(), $"ytLive-sceneorder-{Guid.NewGuid():N}.db"); DbPath = _path; using (var schema = new Services.LayoutStore(_path)) { } SqliteConnection.ClearAllPools(); MainViewModel.LayoutPathOverride = _path; using var connection = new SqliteConnection($"Data Source={_path}"); connection.Open(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = """ INSERT INTO Scene (Id, Name, IsHidden, IsChatScene, HasBackground, SortOrder) VALUES ('scene-starting', 'Starting', 0, 0, 1, 0), ('scene-live', 'Live', 0, 0, 1, 1), ('scene-chat', 'Chat', 0, 1, 1, 2), ('scene-brb', 'BRB', 0, 0, 1, 3), ('scene-ending', 'Ending', 0, 0, 1, 4); """; cmd.ExecuteNonQuery(); } } public void Dispose() { MainViewModel.LayoutPathOverride = null; SqliteConnection.ClearAllPools(); try { File.Delete(_path); } catch { /* best-effort cleanup */ } } } }