using System; using System.Collections.Generic; using System.Linq; using MfGames.Gallium; using MfGames.Nitride.Tests; using NodaTime; using NodaTime.Testing; using Xunit; using Xunit.Abstractions; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using Zio; namespace MfGames.Nitride.Temporal.Schedules.Tests; public class IndexedPathRegexScheduleTest : TemporalSchedulesTestBase { public IndexedPathRegexScheduleTest(ITestOutputHelper output) : base(output) { } [Fact] public void DeserializedSetupWorks() { using TemporalSchedulesTestContext context = this.CreateContext(); // Create a numerical series of entities. var input = new List { new Entity().SetAll((UPath)"/chapter-01.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-02.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-03.md", new TestModel()), }; TestModel model = new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) .Build() .Deserialize( string.Join( "\n", "---", "access: custom", "schedules:", " pathRegex: chapter-(\\d+)", " indexes:", " 1:", " scheduleStart: 2020-01-01", " schedulePeriod: instant", " access: t-1", " 2:", " scheduleStart: 2023-01-02", " schedulePeriod: 1 week", " access: t-2", "")); var schedules = model.Schedules!; // Create the operation and run it, but treat it as being set after the // second but before the third item. TimeService time = context.Resolve(); ApplySchedules op = context.Resolve() .WithGetSchedules(_ => new ISchedule[] { schedules }); var now = Instant.FromUtc(2023, 1, 3, 0, 0); time.Clock = new FakeClock(now); var actual = op .Run(input) .Select( a => string.Format( "{0} -- {1} -- {2}", a.Get().ToString(), a.Has() ? time .ToDateTime(a.Get()) .ToString("yyyy-MM-dd") : "none", a.Get().Access)) .ToList(); var expected = new List { "/chapter-01.md -- 2020-01-01 -- t-1", "/chapter-02.md -- 2023-01-02 -- t-2", "/chapter-03.md -- none -- private", }; TestHelper.CompareObjects(expected, actual); } [Fact] public void ManualSetupWorks() { using TemporalSchedulesTestContext context = this.CreateContext(); // Create a numerical series of entities. var input = new List { new Entity().SetAll((UPath)"/chapter-01.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-02.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-03.md", new TestModel()), }; var schedules = new TestRegexSchedule { Indexes = new Dictionary { [1] = new TestSchedule { ScheduleStart = DateTime.Parse("2023-01-01"), Access = "public", }, }, }; // Create the operation and run it, but treat it as being set after the // second but before the third item. TimeService time = context.Resolve(); ApplySchedules op = context.Resolve() .WithGetSchedules(_ => new ISchedule[] { schedules }); var now = Instant.FromUtc(2023, 1, 9, 0, 0); time.Clock = new FakeClock(now); var actual = op .Run(input) .Select( a => string.Format( "{0} -- {1} -- {2}", a.Get().ToString(), a.Has() ? time .ToDateTime(a.Get()) .ToString("yyyy-MM-dd") : "none", a.Get().Access)) .ToList(); var expected = new List { "/chapter-01.md -- 2023-01-01 -- public", "/chapter-02.md -- 2023-01-08 -- public", "/chapter-03.md -- none -- private", }; TestHelper.CompareObjects(expected, actual); } [Fact] public void SequencedScheduleWorks() { using TemporalSchedulesTestContext context = this.CreateContext(); // Create a numerical series of entities. var input = new List { new Entity().SetAll((UPath)"/chapter-01.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-02.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-03.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-04.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-05.md", new TestModel()), new Entity().SetAll((UPath)"/chapter-06.md", new TestModel()), }; var schedules = new TestRegexSchedule() { Indexes = new Dictionary { [1] = new() { ScheduleStart = DateTime.Parse("2020-01-01"), Access = "subscriber", SchedulePeriodTimeSpan = TimeSpan.FromDays(7), }, [3] = new() { ScheduleStart = DateTime.Parse("2023-01-07"), Access = "public", SchedulePeriodTimeSpan = TimeSpan.Zero, }, [5] = new() { SchedulePeriod = "never", }, }, }; // Create the operation and run it, but treat it as being set after the // second but before the third item. TimeService time = context.Resolve(); ApplySchedules op = context.Resolve() .WithGetSchedules(_ => new ISchedule[] { schedules }); var now = Instant.FromUtc(2023, 1, 9, 0, 0); time.Clock = new FakeClock(now); var actual = op .Run(input) .Select( a => string.Format( "{0} -- {1} -- {2}", a.Get().ToString(), a.Has() ? time .ToDateTime(a.Get()) .ToString("yyyy-MM-dd") : "none", a.Get().Access)) .ToList(); var expected = new List { "/chapter-01.md -- 2020-01-01 -- subscriber", "/chapter-02.md -- 2020-01-08 -- subscriber", "/chapter-03.md -- 2023-01-07 -- public", "/chapter-04.md -- 2023-01-07 -- public", "/chapter-05.md -- none -- private", "/chapter-06.md -- none -- private", }; TestHelper.CompareObjects(expected, actual); } public class TestModel { public string? Access { get; set; } = "private"; public TestRegexSchedule? Schedules { get; set; } } public class TestRegexSchedule : IndexedPathRegexSchedule { } public class TestSchedule : IndexedSchedule { public TestSchedule() { this.SchedulePeriod = "1 week"; } public string? Access { get; set; } /// protected override Entity Apply( Entity entity, int number, Instant instant) { TestModel model = entity.Get(); model.Access = this.Access; return entity.SetAll(instant, model); } } }