using TeleWave.Domain.Programming; using Xunit; namespace TeleWave.Domain.Tests.Programming; public class GroupTests { private static IReadOnlyList Order(Group group) => group.Items.OrderBy(i => i.Position).Select(i => i.Id).ToList(); [Fact] public void AddElement_AppendsAndRejectsDuplicates() { var group = Group.Create("Боевики 90-х"); var showId = Guid.NewGuid(); Assert.NotNull(group.AddElement(GroupElementKind.Show, showId)); Assert.Null(group.AddElement(GroupElementKind.Show, showId)); Assert.Single(group.Items); } [Fact] public void AddElement_SameIdDifferentKind_AreDistinct() { var group = Group.Create("Смешанная"); var id = Guid.NewGuid(); group.AddElement(GroupElementKind.Show, id); group.AddElement(GroupElementKind.Collection, id); Assert.Equal(2, group.Items.Count); } [Fact] public void RemoveElement_DropsAllMatchingPositions() { var group = Group.Create("Боевики"); var showId = Guid.NewGuid(); group.AddElement(GroupElementKind.Show, showId); group.AddElement(GroupElementKind.Show, Guid.NewGuid()); var removed = group.RemoveElement(GroupElementKind.Show, showId); Assert.Equal(1, removed); Assert.Single(group.Items); } [Fact] public void SetWeight_ClampsNegativeToZero() { var group = Group.Create("Боевики"); var item = group.AddElement(GroupElementKind.Show, Guid.NewGuid())!; group.SetWeight(item.Id, -5); // Ноль — законный вес («исключить, не удаляя»), отрицательный сломал бы взвешенный выбор. Assert.Equal(0, item.Weight); } [Fact] public void SetWeight_UnknownItem_ReturnsFalse() { var group = Group.Create("Боевики"); Assert.False(group.SetWeight(Guid.NewGuid(), 3)); } [Fact] public void Reorder_KeepsUnmentionedAfterRequested() { var group = Group.Create("Боевики"); var a = group.AddElement(GroupElementKind.Show, Guid.NewGuid())!; var b = group.AddElement(GroupElementKind.Show, Guid.NewGuid())!; var c = group.AddElement(GroupElementKind.Show, Guid.NewGuid())!; group.Reorder([c.Id]); Assert.Equal([c.Id, a.Id, b.Id], Order(group)); } [Fact] public void SetFilter_TreatsBlankAsAbsent() { var group = Group.Create("Боевики"); group.SetFilter(" "); Assert.Null(group.FilterJson); } [Fact] public void UpdateStats_StoresSnapshot() { var group = Group.Create("Боевики"); var at = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero); group.UpdateStats(3, 42, TimeSpan.FromHours(18), at); Assert.Equal(3, group.ItemCount); Assert.Equal(42, group.UnitCount); Assert.Equal(TimeSpan.FromHours(18), group.TotalDuration); Assert.Equal(at, group.StatsComputedAt); } [Fact] public void SetMode_ToDynamic_KeepsItemsAsPinned() { // Смена режима не должна вымывать из эфира то, что уже стояло в слотах. var group = Group.Create("Боевики"); var show = Guid.NewGuid(); group.AddElement(GroupElementKind.Show, show); group.SetMode(GroupMode.Dynamic); Assert.Equal(GroupMode.Dynamic, group.Mode); Assert.Equal(GroupItemRole.Pinned, group.Items.Single().Role); } [Fact] public void SetMode_BackToStatic_DropsExclusionsAndUnpins() { var group = Group.Create("Боевики"); group.SetMode(GroupMode.Dynamic); group.AddElement(GroupElementKind.Show, Guid.NewGuid()); group.Exclude(GroupElementKind.Show, Guid.NewGuid()); group.SetMode(GroupMode.Static); // Исключать в статической группе нечего: состав и есть список. var item = Assert.Single(group.Items); Assert.Equal(GroupItemRole.Member, item.Role); } [Fact] public void SetMode_SameMode_ChangesNothing() { var group = Group.Create("Боевики"); group.AddElement(GroupElementKind.Show, Guid.NewGuid()); group.SetMode(GroupMode.Static); Assert.Equal(GroupItemRole.Member, group.Items.Single().Role); } [Fact] public void AddElement_InDynamicGroup_PinsByDefault() { // Иначе правило вымело бы позицию на первом же обращении. var group = Group.Create("Боевики"); group.SetMode(GroupMode.Dynamic); var item = group.AddElement(GroupElementKind.Show, Guid.NewGuid()); Assert.Equal(GroupItemRole.Pinned, item!.Role); } [Fact] public void Exclude_TurnsPinnedIntoExclusion() { // Держать на один элемент обе противоположные поправки нельзя. var group = Group.Create("Боевики"); group.SetMode(GroupMode.Dynamic); var show = Guid.NewGuid(); group.AddElement(GroupElementKind.Show, show); Assert.True(group.Exclude(GroupElementKind.Show, show)); Assert.Equal(GroupItemRole.Excluded, group.Items.Single().Role); } [Fact] public void Exclude_InStaticGroup_IsRefused() { var group = Group.Create("Боевики"); Assert.False(group.Exclude(GroupElementKind.Show, Guid.NewGuid())); Assert.Empty(group.Items); } [Fact] public void RemoveExclusion_ReturnsElementToTheRule() { var group = Group.Create("Боевики"); group.SetMode(GroupMode.Dynamic); var show = Guid.NewGuid(); group.Exclude(GroupElementKind.Show, show); Assert.True(group.RemoveExclusion(GroupElementKind.Show, show)); Assert.Empty(group.Items); // Снимать нечего — второй раз это уже не поправка. Assert.False(group.RemoveExclusion(GroupElementKind.Show, show)); } }