using System; using System.Collections.ObjectModel; using System.IO; using System.Linq; using Xunit; using ytLive.Models; using ytLive.Services; namespace ytLive.Tests; /// /// The alert sound byte (creator ruling 2026-11-01): a file that plays with the alert clip, with an /// optional loop. It is configured on the alert layer, so it has to survive a save/reload — the /// same startup path that a missing SELECT column broke once already. /// public class AlertAudioPersistenceTests { [Fact] public void The_sound_byte_and_its_loop_flag_survive_a_save_and_reload() { var dbPath = Path.Combine(Path.GetTempPath(), $"llamacasty-alertaudio-{Guid.NewGuid():N}.db"); try { var scenes = new ObservableCollection { new() { Name = SceneCatalog.Live } }; var alert = new Source { Name = "Stream Alerts", Type = SourceType.AlertBox, X = 620, Y = 430, Width = 680, Height = 200, AlertAudioPath = @"C:\sounds\ding.wav", AlertAudioLoop = true, }; scenes[0].Elements.Add(alert); using (var store = new LayoutStore(dbPath)) store.Save(scenes, null, null); using (var reopened = new LayoutStore(dbPath)) { var loaded = reopened.Load().SelectMany(s => s.Elements).OfType() .Single(s => s.Type == SourceType.AlertBox); Assert.Equal(@"C:\sounds\ding.wav", loaded.AlertAudioPath); Assert.True(loaded.AlertAudioLoop); Assert.Equal("ding.wav", loaded.AlertAudioFileDisplay); Assert.True(loaded.HasAlertAudio); } } finally { try { File.Delete(dbPath); } catch (IOException) { } } } [Fact] public void A_fresh_alert_layer_has_no_sound_byte_and_does_not_loop() { var alert = new Source { Type = SourceType.AlertBox }; Assert.False(alert.HasAlertAudio); Assert.False(alert.AlertAudioLoop); Assert.Equal("No sound byte", alert.AlertAudioFileDisplay); } }