using TeleWave.Domain.Programming; using Xunit; namespace TeleWave.Domain.Tests.Programming; /// /// Шаблон стыка: порядок врезок и развилки. Главный инвариант — врезки одной развилки лежат /// непрерывным отрезком: развилка занимает одно место в цепочке, и разбросанные участники /// не имели бы смысла. /// public class JunctionTemplateTests { private static JunctionElementSettings Settings( JunctionElementKind kind = JunctionElementKind.Ad, Guid? groupId = null, Guid? bumperTemplateId = null, Guid? bumperVariantId = null, JunctionAmountMode amountMode = JunctionAmountMode.Count, int amountValue = 1, bool isRequired = false, string? choiceKey = null, int choiceWeight = 1, string? conditionsJson = null ) => new( kind, groupId, bumperTemplateId, bumperVariantId, amountMode, amountValue, isRequired, choiceKey, choiceWeight, conditionsJson ); [Fact] public void Create_TrimsName_AndStartsEmpty() { var junction = JunctionTemplate.Create(" Прайм "); Assert.Equal("Прайм", junction.Name); Assert.Null(junction.MaxTotalSeconds); Assert.Empty(junction.Elements); Assert.NotEqual(Guid.Empty, junction.Id); } [Fact] public void Update_DropsNonPositiveCap() { var junction = JunctionTemplate.Create("Прайм"); junction.Update(" Ночь ", 120); Assert.Equal("Ночь", junction.Name); Assert.Equal(120, junction.MaxTotalSeconds); junction.Update("Ночь", 0); Assert.Null(junction.MaxTotalSeconds); } [Fact] public void AddElement_AppendsWithNextPosition() { var junction = JunctionTemplate.Create("Прайм"); var first = junction.AddElement(JunctionElementKind.Ad); var second = junction.AddElement(JunctionElementKind.Bumper); Assert.Equal(0, first.Position); Assert.Equal(1, second.Position); Assert.Equal(second, junction.FindElement(second.Id)); Assert.Null(junction.FindElement(Guid.NewGuid())); } [Fact] public void RemoveElement_RenumbersRest() { var junction = JunctionTemplate.Create("Прайм"); var first = junction.AddElement(JunctionElementKind.Ad); var second = junction.AddElement(JunctionElementKind.Promo); var third = junction.AddElement(JunctionElementKind.Filler); Assert.True(junction.RemoveElement(first.Id)); Assert.False(junction.RemoveElement(Guid.NewGuid())); Assert.Equal(0, second.Position); Assert.Equal(1, third.Position); } [Fact] public void Reorder_PutsRequestedFirst_AndKeepsRestBehind() { var junction = JunctionTemplate.Create("Прайм"); var first = junction.AddElement(JunctionElementKind.Ad); var second = junction.AddElement(JunctionElementKind.Promo); var third = junction.AddElement(JunctionElementKind.Filler); junction.Reorder([third.Id, first.Id]); Assert.Equal(0, third.Position); Assert.Equal(1, first.Position); // Не упомянутые остаются позади, сохраняя относительный порядок. Assert.Equal(2, second.Position); } [Fact] public void Reorder_PullsForkMembersTogether() { var junction = JunctionTemplate.Create("Прайм"); var ad = junction.AddElement(JunctionElementKind.Ad); var promo = junction.AddElement(JunctionElementKind.Promo); var filler = junction.AddElement(JunctionElementKind.Filler); ad.SetChoice("fork", 1); filler.SetChoice("fork", 3); junction.Reorder([ad.Id, promo.Id, filler.Id]); // Развилка приезжает к первому упоминанию метки — между ними чужой врезке места нет. Assert.Equal(0, ad.Position); Assert.Equal(1, filler.Position); Assert.Equal(2, promo.Position); } [Fact] public void Reorder_MovesWholeFork_ByAnyMember() { var junction = JunctionTemplate.Create("Прайм"); var bumper = junction.AddElement(JunctionElementKind.Bumper); var ad = junction.AddElement(JunctionElementKind.Ad); var promo = junction.AddElement(JunctionElementKind.Promo); ad.SetChoice("fork", 1); promo.SetChoice("fork", 1); // Тащим за второго участника — развилка переезжает целиком. junction.Reorder([promo.Id, bumper.Id]); Assert.Equal(0, promo.Position); Assert.Equal(1, ad.Position); Assert.Equal(2, bumper.Position); } [Fact] public void ElementUpdate_KeepsOnlySourceOfItsKind() { var junction = JunctionTemplate.Create("Прайм"); var element = junction.AddElement(JunctionElementKind.Ad); var group = Guid.NewGuid(); var template = Guid.NewGuid(); var variant = Guid.NewGuid(); element.Update(Settings(groupId: group, bumperTemplateId: template, amountValue: 4)); Assert.Equal(group, element.GroupId); // Ссылка от чужого типа потом читалась бы генератором как настройка. Assert.Null(element.BumperTemplateId); Assert.Equal(4, element.AmountValue); element.Update( Settings( kind: JunctionElementKind.Bumper, groupId: group, bumperTemplateId: template, bumperVariantId: variant ) ); Assert.Null(element.GroupId); Assert.Equal(template, element.BumperTemplateId); Assert.Equal(variant, element.BumperVariantId); } [Fact] public void ElementUpdate_ClampsValues_AndBlankStringsBecomeNull() { var junction = JunctionTemplate.Create("Прайм"); var element = junction.AddElement(JunctionElementKind.Ad); element.Update( Settings( groupId: Guid.NewGuid(), amountValue: 0, choiceKey: " ", choiceWeight: -5, conditionsJson: " " ) ); Assert.Equal(1, element.AmountValue); Assert.Null(element.ChoiceKey); Assert.Equal(0, element.ChoiceWeight); Assert.Null(element.ConditionsJson); } [Fact] public void SetChoice_TrimsKey_AndClampsWeight() { var junction = JunctionTemplate.Create("Прайм"); var element = junction.AddElement(JunctionElementKind.Ad); element.SetChoice(" fork ", -2); Assert.Equal("fork", element.ChoiceKey); Assert.Equal(0, element.ChoiceWeight); element.SetChoice(null, 3); Assert.Null(element.ChoiceKey); Assert.Equal(3, element.ChoiceWeight); } }