using System; using System.IO; using Microsoft.Data.Sqlite; using Xunit; using ytLive.Models; using ytLive.Services; using ytLive.ViewModels; namespace ytLive.Tests; /// /// Top bar redesign — the bar is ONE surface rendered by the FIRST decision /// (Record or Stream). Each world is the whole bar: Test is a child of Stream, /// but the account zone (Sign In / avatar) is WORLD-INDEPENDENT (creator /// 2026-09-23) so the right column never pops in and out and the bar height /// stays pinned. The switch is a two-position gate, so "going back" is one tap /// on the other segment. While running, the switch retires and a single reality /// line (dot + word + elapsed) + End replace it. /// [Collection("RealApp")] public sealed class TopBarModeTests { private readonly RealAppHost _app; public TopBarModeTests(RealAppHost app) => _app = app; [Fact] public void TopBar_Renders_Only_The_Armed_World() { _app.Run(Run); } private void Run() { var tempDb = Path.Combine(Path.GetTempPath(), $"ytLlive-topbar-{Guid.NewGuid():N}.db"); MainViewModel.LayoutPathOverride = tempDb; try { using (var schema = new LayoutStore(tempDb)) { } SqliteConnection.ClearAllPools(); var vm = new MainViewModel(); // The dev machine may hold a real saved OAuth session (loads synchronously // during the ctor), so the sign-in state is forced deterministically. vm.IsConnected = false; // Default (nothing armed) = the Record world: Go says "Start Recording", // no Test — but the account zone is app-level and stays (signed out → // Sign In visible even here; no avatar). Assert.True(vm.ShowIdleWorld); Assert.True(vm.ShowRecordAction); Assert.False(vm.ShowStreamActions); Assert.True(vm.ShowSignInButton); Assert.False(vm.ShowAvatarButton); Assert.False(vm.ShowTestButton); Assert.Equal("Start Recording", vm.PrimaryStartButtonLabel); // Arming ON-AIR switches the whole bar to the Stream world. vm.OnAirPillOn = true; Assert.False(vm.ShowRecordAction); Assert.True(vm.ShowStreamActions); // Signed out: the account zone shows Sign In; no avatar; Test is gated // behind the sign-in (Test rides on Stream AND a connected account). Assert.True(vm.ShowSignInButton); Assert.False(vm.ShowAvatarButton); Assert.False(vm.ShowTestButton); Assert.Equal("Go Live", vm.PrimaryStartButtonLabel); // Connected: avatar + Test join the Stream world; Sign In retires. vm.IsConnected = true; Assert.False(vm.ShowSignInButton); Assert.True(vm.ShowAvatarButton); Assert.True(vm.ShowTestButton); // Going back is one tap: flipping REC returns the bar to the Record world — // the avatar STAYS (world-independent account zone), only Test retires. vm.RecordPillOn = true; Assert.False(vm.ShowStreamActions); Assert.True(vm.ShowRecordAction); Assert.True(vm.ShowAvatarButton); Assert.False(vm.ShowTestButton); Assert.Equal("Start Recording", vm.PrimaryStartButtonLabel); // Running retires the switch and worlds; the reality line pins the mode. vm.RecordPillOn = false; vm.OnAirPillOn = true; vm.IsRecording = true; Assert.False(vm.ShowIdleWorld); Assert.True(vm.RunningVisible); Assert.Equal("REC", vm.RunningText); Assert.Equal("#22c55e", vm.RunningDotBrush); vm.IsRecording = false; vm.StreamStatus = StreamStatus.Streaming; Assert.Equal("LIVE", vm.RunningText); Assert.Equal("#e94560", vm.RunningDotBrush); vm.IsTestStream = true; Assert.Equal("TEST", vm.RunningText); Assert.Equal("#9c6f1c", vm.RunningDotBrush); } finally { MainViewModel.LayoutPathOverride = null; SqliteConnection.ClearAllPools(); try { File.Delete(tempDb); } catch { /* best-effort cleanup */ } } } }