Enhance channel and settings functionalities: introduce viewer settings in ChannelEndpoints, update SiteSettings to include channel number toggling, and refactor related data structures. Implement new endpoints for validating templates and diffing scheduling changes, improving overall user experience and configuration management.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
using TeleWave.Application.Programming.Templates;
|
||||
using TeleWave.Domain.Library;
|
||||
using Xunit;
|
||||
|
||||
namespace TeleWave.Application.Tests.Programming;
|
||||
|
||||
/// <summary>Окна детского времени: разрешение по времени суток, включая переход через полночь.</summary>
|
||||
public class PlanningRulesTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(7, 0, true)]
|
||||
[InlineData(22, 59, true)]
|
||||
[InlineData(6, 0, true)] // ровно начало
|
||||
[InlineData(23, 0, false)] // ровно конец — уже вне окна
|
||||
[InlineData(2, 0, false)]
|
||||
public void AudienceAt_DayWindow(int hour, int minute, bool inside)
|
||||
{
|
||||
var rules = new PlanningRules(
|
||||
[new AudienceWindow(new TimeOnly(6, 0), new TimeOnly(23, 0), ShowAudience.Teen)]
|
||||
);
|
||||
|
||||
var result = rules.AudienceAt(new TimeOnly(hour, minute));
|
||||
|
||||
Assert.Equal(inside ? ShowAudience.Teen : null, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(23, 30, true)]
|
||||
[InlineData(3, 0, true)]
|
||||
[InlineData(12, 0, false)]
|
||||
public void AudienceAt_WindowCrossingMidnight(int hour, int minute, bool inside)
|
||||
{
|
||||
// «С 23:00 до 06:00» — ночное окно, границы сравниваются в обратную сторону.
|
||||
var rules = new PlanningRules(
|
||||
[new AudienceWindow(new TimeOnly(23, 0), new TimeOnly(6, 0), ShowAudience.Adult)]
|
||||
);
|
||||
|
||||
var result = rules.AudienceAt(new TimeOnly(hour, minute));
|
||||
|
||||
Assert.Equal(inside ? ShowAudience.Adult : null, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudienceAt_OverlappingWindows_TakesTheStrictest()
|
||||
{
|
||||
// Широкое окно, случайно наложенное поверх детского, не должно его отменять.
|
||||
var rules = new PlanningRules(
|
||||
[
|
||||
new AudienceWindow(new TimeOnly(6, 0), new TimeOnly(23, 0), ShowAudience.General),
|
||||
new AudienceWindow(new TimeOnly(7, 0), new TimeOnly(10, 0), ShowAudience.Kids),
|
||||
]
|
||||
);
|
||||
|
||||
Assert.Equal(ShowAudience.Kids, rules.AudienceAt(new TimeOnly(8, 0)));
|
||||
Assert.Equal(ShowAudience.General, rules.AudienceAt(new TimeOnly(12, 0)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudienceAt_WithoutWindows_IsUnlimited()
|
||||
{
|
||||
Assert.Null(new PlanningRules().AudienceAt(new TimeOnly(3, 0)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Json_RoundTrips()
|
||||
{
|
||||
var rules = new PlanningRules(
|
||||
[new AudienceWindow(new TimeOnly(6, 0), new TimeOnly(23, 0), ShowAudience.Teen)],
|
||||
new RepeatLimitRule(7, 2),
|
||||
MaxBreakMinutesPerHour: 12,
|
||||
MaxGenreSharePercent: 40,
|
||||
MaxFallbackSharePercent: 15
|
||||
);
|
||||
|
||||
var restored = PlanningRules.FromJson(rules.ToJson());
|
||||
|
||||
// Сравниваем по полям: у record со списком внутри равенство ссылочное, и `Assert.Equal`
|
||||
// на самих правилах проверял бы не то.
|
||||
Assert.NotNull(restored);
|
||||
Assert.Equal(rules.MaxAudienceByTime!, restored.MaxAudienceByTime!);
|
||||
Assert.Equal(rules.MaxRepeatsInWindow, restored.MaxRepeatsInWindow);
|
||||
Assert.Equal(rules.MaxBreakMinutesPerHour, restored.MaxBreakMinutesPerHour);
|
||||
Assert.Equal(rules.MaxGenreSharePercent, restored.MaxGenreSharePercent);
|
||||
Assert.Equal(rules.MaxFallbackSharePercent, restored.MaxFallbackSharePercent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromJson_Garbage_IsNull()
|
||||
{
|
||||
// Битый JSON не должен ронять генерацию: правило просто считается незаданным.
|
||||
Assert.Null(PlanningRules.FromJson("{"));
|
||||
Assert.Null(PlanningRules.FromJson(null));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user