ScoreboardRecorder owns the one scope the numbers promise. StartSession resets and marks running; Record ignores everything outside a session (a stale tally from the last stream is exactly the 'today' lie this design avoids); EndSession freezes the numbers but stops them moving, so an End screen can still show them. Changed fires only when a displayed value actually moves, which is what keeps the strip's raster cache honest.
43 lines
1.5 KiB
C#
43 lines
1.5 KiB
C#
using Xunit;
|
|
using ytLive.Models;
|
|
|
|
namespace ytLive.Tests;
|
|
|
|
/// <summary>The session is the only scope the scoreboard promises, so the rules are: a start clears
|
|
/// everything, events outside a session are ignored, and an ended session keeps its numbers but
|
|
/// stops moving.</summary>
|
|
public class ScoreboardRecorderTests
|
|
{
|
|
private static ChatMessage Member(string name) => new() { Kind = ChatEventKind.NewMember, AuthorName = name };
|
|
|
|
[Fact]
|
|
public void Starting_a_session_clears_the_tallies_and_only_a_live_session_counts()
|
|
{
|
|
var recorder = new ScoreboardRecorder();
|
|
var changes = 0;
|
|
recorder.Changed += () => changes++;
|
|
|
|
// Outside a session: nothing is counted (no stale carry-over from the last stream).
|
|
recorder.Record(Member("Ignored"));
|
|
Assert.Equal(0, recorder.State.NewMembers);
|
|
|
|
recorder.StartSession();
|
|
Assert.True(recorder.IsRunning);
|
|
recorder.Record(Member("First"));
|
|
recorder.Record(Member("Second"));
|
|
Assert.Equal(2, recorder.State.NewMembers);
|
|
Assert.True(changes >= 2, "each visible change must raise Changed so the strip re-renders");
|
|
|
|
// End freezes: numbers stay, movement stops.
|
|
recorder.EndSession();
|
|
Assert.False(recorder.IsRunning);
|
|
recorder.Record(Member("AfterEnd"));
|
|
Assert.Equal(2, recorder.State.NewMembers);
|
|
|
|
// The next session starts from zero.
|
|
recorder.StartSession();
|
|
Assert.Equal(0, recorder.State.NewMembers);
|
|
Assert.Null(recorder.State.LastMemberName);
|
|
}
|
|
}
|