Files

125 lines
4.7 KiB
C#

using System;
using System.IO;
using System.Linq;
using Microsoft.Data.Sqlite;
using Xunit;
using ytLive.Models;
using ytLive.ViewModels;
namespace ytLive.Tests;
/// <summary>
/// TASK 27 integration: the (+) menu's YouTube Chat row gates on one chat layer
/// per layout (same rule as the webcam's app-wide identity), and ChatBox layers
/// created before the "YouTube Chat" default (legacy name "Chat") heal to the
/// picklist's label on load — creator renames stay untouched.
/// Real-App + temp-DB pattern (see WebcamMenuGateTests).
/// </summary>
[Collection("RealApp")]
public sealed class ChatLayerGateTests
{
[Fact]
public void LegacyChatName_Heals_And_CanAddYouTubeChat_Gates_On_The_Existing_Layer()
{
_app.Run(Run);
}
private readonly RealAppHost _app;
public ChatLayerGateTests(RealAppHost app) => _app = app;
private void Run()
{
var tempDb = Path.Combine(Path.GetTempPath(), $"ytLlive-chatgate-{Guid.NewGuid():N}.db");
MainViewModel.LayoutPathOverride = tempDb;
var window = default(MainWindow);
try
{
using (var schema = new ytLive.Services.LayoutStore(tempDb)) { }
SqliteConnection.ClearAllPools();
SeedDatabaseWithLegacyChatLayer(tempDb);
window = new MainWindow();
var vm = (MainViewModel)window.DataContext;
var starting = vm.Scenes.Single(s => SceneCatalog.Is(s.Name, SceneCatalog.Starting));
var live = vm.Scenes.Single(s => SceneCatalog.Is(s.Name, SceneCatalog.Live));
var chatLayer = Assert.Single(starting.Elements.OfType<Source>()
.Where(s => s.Type == SourceType.ChatBox).ToList());
Assert.Equal("YouTube Chat", chatLayer.Name);
vm.StagedScene = live;
Assert.False(vm.CanAddYouTubeChat,
"chat layer exists in another scene — Add YouTube Chat must be greyed out");
vm.StagedScene = starting;
Assert.False(vm.CanAddYouTubeChat, "staged scene itself has the chat layer");
vm.SaveLayoutNow();
using (var connection = new SqliteConnection($"Data Source={tempDb}"))
{
connection.Open();
using var names = connection.CreateCommand();
names.CommandText =
"SELECT Name FROM Source WHERE Type = 'ChatBox';";
Assert.Equal("YouTube Chat", (string)names.ExecuteScalar()!);
}
vm.RemoveSourceCommand.Execute(chatLayer);
Assert.True(vm.CanAddYouTubeChat,
"the only chat layer was removed — the (+) item re-enables");
}
finally
{
window?.Close();
MainViewModel.LayoutPathOverride = null;
SqliteConnection.ClearAllPools();
try { File.Delete(tempDb); } catch { /* best-effort cleanup */ }
}
}
/// <summary>Five canonical scenes + a ChatBox layer still carrying the
/// pre-rename default name "Chat" in Starting.</summary>
private static void SeedDatabaseWithLegacyChatLayer(string path)
{
using var connection = new SqliteConnection($"Data Source={path}");
connection.Open();
var scenes = new (string Id, string Name)[]
{
("scene-starting", "Starting"),
("scene-live", "Live"),
("scene-brb", "BRB"),
("scene-chat", "Chat"),
("scene-ending", "Ending"),
};
foreach (var (id, name) in scenes)
{
using var cmd = connection.CreateCommand();
cmd.CommandText =
"INSERT INTO Scene (Id, Name, HasBackground, SortOrder) VALUES ($id, $name, 1, $order);";
cmd.Parameters.AddWithValue("$id", id);
cmd.Parameters.AddWithValue("$name", name);
cmd.Parameters.AddWithValue("$order", Array.IndexOf(scenes, (id, name)));
cmd.ExecuteNonQuery();
}
using (var background = connection.CreateCommand())
{
background.CommandText =
@"INSERT INTO Source (Id, SceneId, Type, Name, IsEnabled, X, Y, Width, Height, IsBackground, SortOrder)
VALUES ('bg-1', 'scene-starting', 'Background', 'Background', 1, 0, 0, 1920, 1080, 1, 0);";
background.ExecuteNonQuery();
}
using (var chat = connection.CreateCommand())
{
chat.CommandText =
@"INSERT INTO Source (Id, SceneId, Type, Name, IsEnabled, X, Y, Width, Height, IsBackground, SortOrder)
VALUES ('chat-1', 'scene-starting', 'ChatBox', 'Chat', 1, 1400, 20, 500, 648, 0, 1);";
chat.ExecuteNonQuery();
}
}
}