feat(scoreboard): the layer is available to ALL scenes (YT_ACTIVITY_TICKER)
Creator ruling: the Scoreboard layer exists in every scene rather than being added five times. ScoreboardHealer.Ensure keeps exactly one per scene — healed on load like the Background and Brand logo — so a scene can never end up with two, and 'off' is the ordinary per-scene eye toggle rather than a delete. It is appended as the TOPMOST layer on purpose: a full-width strip draws over the scene, and inserting it above the background would break the Brand logo's documented invariant (directly above the background). That choice is also why the layer-reorder test still passes untouched. Also: a layer-list icon for the type, so the row is not blank. Guard: ScoreboardHealerTests — one per scene, topmost, exact strip geometry, idempotent, and a duplicate healed back to one.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using ytLive.Models;
|
||||
|
||||
namespace ytLive.Tests;
|
||||
|
||||
/// <summary>Creator ruling (2026-10-30): the Scoreboard layer — YT_ACTIVITY_TICKER — is AVAILABLE TO
|
||||
/// ALL SCENES. It therefore heals into every scene like the Background and Brand logo, and a scene
|
||||
/// can never end up with two of them.</summary>
|
||||
public class ScoreboardHealerTests
|
||||
{
|
||||
private static Scene SceneWith(string name)
|
||||
{
|
||||
var scene = new Scene { Name = name };
|
||||
scene.Elements.Add(new Source { Name = "Background", Type = SourceType.Background, IsBackground = true });
|
||||
scene.Elements.Add(new Source { Name = "Brand logo", Type = SourceType.Image, IsBrandLogo = true });
|
||||
return scene;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_scene_gets_exactly_one_scoreboard_below_the_background()
|
||||
{
|
||||
var scenes = new List<Scene>
|
||||
{
|
||||
SceneWith(SceneCatalog.Starting), SceneWith(SceneCatalog.Live), SceneWith(SceneCatalog.Brb),
|
||||
};
|
||||
|
||||
Assert.True(ScoreboardHealer.Ensure(scenes));
|
||||
foreach (var scene in scenes)
|
||||
{
|
||||
var boards = scene.Elements.OfType<Source>().Where(s => s.IsScoreboard).ToList();
|
||||
Assert.Single(boards);
|
||||
Assert.Equal("Scoreboard", boards[0].Name);
|
||||
Assert.Equal(0, boards[0].X);
|
||||
Assert.Equal(1920, boards[0].Width);
|
||||
Assert.Equal(ScoreboardHealer.StripHeight, boards[0].Height);
|
||||
// Topmost: a full-width strip over the scene, and the Brand logo keeps its documented
|
||||
// place directly above the background.
|
||||
Assert.Equal(scene.Elements.Count - 1, scene.Elements.IndexOf(boards[0]));
|
||||
Assert.Equal("Brand logo", scene.Elements[1].Name);
|
||||
}
|
||||
|
||||
// Idempotent: a second pass changes nothing (no duplicate strips, no churn).
|
||||
Assert.False(ScoreboardHealer.Ensure(scenes));
|
||||
foreach (var scene in scenes) Assert.Single(scene.Elements.OfType<Source>().Where(s => s.IsScoreboard));
|
||||
|
||||
// A scene that somehow has two is healed back to one.
|
||||
scenes[0].Elements.Add(new Source { Name = "Scoreboard2", Type = SourceType.Scoreboard });
|
||||
Assert.True(ScoreboardHealer.Ensure(scenes));
|
||||
Assert.Single(scenes[0].Elements.OfType<Source>().Where(s => s.IsScoreboard));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user