Files
LlamaCasty/ytLive.Tests/LayoutStoreSnapshotTests.cs
T
gramps 37791086ae feat(37): keep a default layout snapshot beside the current layout
The matching-build persistence slice is in place: existing layouts are captured
once as defaults, first-run factory scenes are saved and captured before the
creator can edit, and same-build startup continues to load current rows. Default
asset references survive current-layout saves.

One integration test covers the current-layout roundtrip and immutable default.
609 tests green, clean build with 0 warnings.

Reference scan: OBS stores scene collections separately from output profiles;
this split keeps layout state independent in the same SQLite store:
https://obsproject.com/kb/scene-collections
2026-11-10 17:45:39 -08:00

65 lines
2.1 KiB
C#

using System;
using System.IO;
using System.Linq;
using Microsoft.Data.Sqlite;
using Xunit;
using ytLive.Models;
using ytLive.Services;
namespace ytLive.Tests;
public sealed class LayoutStoreSnapshotTests
{
[Fact]
public void SameBuild_OpensCurrentLayout_WithoutChangingDefaultSnapshot()
{
var path = Path.Combine(Path.GetTempPath(), $"ytLlive-layout-snapshot-{Guid.NewGuid():N}.db");
const string buildId = "build-a";
try
{
using (var store = new LayoutStore(path))
{
var factory = MakeScene("Factory title");
store.Save(new[] { factory }, null, null);
store.PrepareLayoutSnapshots(buildId);
store.Save(new[] { MakeScene("Creator edit") }, null, null);
}
using (var reopened = new LayoutStore(path))
{
reopened.PrepareLayoutSnapshots(buildId);
var current = Assert.Single(reopened.Load());
Assert.Equal("Creator edit", Assert.Single(current.Elements.OfType<Source>()).Name);
using var connection = GetConnection(path);
using var command = connection.CreateCommand();
command.CommandText = "SELECT Value FROM LayoutSnapshotState WHERE Key = 'CurrentBuildId';";
Assert.Equal(buildId, command.ExecuteScalar());
command.CommandText = "SELECT Name FROM DefaultSource;";
Assert.Equal("Factory title", command.ExecuteScalar());
}
}
finally
{
SqliteConnection.ClearAllPools();
try { File.Delete(path); } catch { /* best-effort cleanup */ }
}
}
private static Scene MakeScene(string sourceName)
=> new()
{
Name = SceneCatalog.Starting,
Elements = { new Source { Name = sourceName, Type = SourceType.TextOverlay } },
};
private static SqliteConnection GetConnection(string path)
{
var connection = new SqliteConnection($"Data Source={path}");
connection.Open();
return connection;
}
}