using Microsoft.Extensions.Logging; using Moq; using PARR.DAL.Contracts; using PARR.DAL.DomainModels; using PARR.DAL.Models; using PARR.DAL.NextRunServices.Subservices; using PARR.DAL.Services.Interfaces; namespace PARR.DAL.Tests.TransformServices { public class EsppScheduleTransformServiceTests { private Mock esppSchTypeConfigServiceMock; //private Mock nextRunModifierServiceMock; private ILogger logger; private EsppScheduleTransformService service; public EsppScheduleTransformServiceTests() { esppSchTypeConfigServiceMock = new Mock(); //nextRunModifierServiceMock = new Mock(); var loggerFactory = new LoggerFactory(); logger = loggerFactory.CreateLogger(); service = new EsppScheduleTransformService( logger, esppSchTypeConfigServiceMock.Object //nextRunModifierServiceMock.Object ); } [Fact] public async Task GetNextDate_Monthly2_ReturnsSameDateForAllReferenceDates() { // Arrange var pastDate = new DateTimeOffset(2024, 10, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureNonMatchingDate = new DateTimeOffset(2025, 12, 08, 10, 0, 0, TimeSpan.Zero); // Будущее, не среда и до ожидаемой даты var futureMatchingDate = new DateTimeOffset(2025, 12, 10, 10, 0, 0, TimeSpan.Zero); // Вторая среда и совпадает с ожидаемой датой var expectedDate = futureMatchingDate; var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Monthly2, Name = "Ежемесячно-2", Description = "Расписание по дням недели в месяце" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "Порядок", Description = "Порядковый номер дня недели" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Второй", EsppExportValue = "Второй (экспорт)", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 2 } }, new EsppScheduleValDto { Order = 2, Type = new EsppSchType { Id = 2, Name = "День недели", Description = "День недели (например, понедельник)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Среда", EsppExportValue = "Среда", TypeId = 2, DateCreated = DateTimeOffset.UtcNow, Order = 3 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); //Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureMatchingDate); //Assert Assert.Equal(expectedDate, resultFromPast); Assert.Equal(expectedDate, resultFromFutureNonMatching); Assert.Equal(expectedDate, resultFromFutureMatching); } [Fact] public async Task GetNextDate_Monthly_ReturnsSameDateForAllReferenceDates() { // Arrange var pastDate = new DateTimeOffset(2024, 10, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureNonMatchingDate = new DateTimeOffset(2025, 12, 08, 10, 0, 0, TimeSpan.Zero); // Будущее, не 15-е var futureMatchingDate = new DateTimeOffset(2025, 12, 15, 10, 0, 0, TimeSpan.Zero); // 15-е декабря — совпадает с ожидаемой датой var expectedDate = futureMatchingDate; var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Monthly, Name = "Ежемесячно", Description = "Расписание по числу месяца" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "День месяца", Description = "Число месяца" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "15", EsppExportValue = "15-е число", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureMatchingDate); Assert.Equal(expectedDate, resultFromPast); Assert.Equal(expectedDate, resultFromFutureNonMatching); Assert.Equal(expectedDate, resultFromFutureMatching); } [Fact] public async Task GetNextDate_Annually_ReturnsSameDateForAllReferenceDates() { // Arrange var pastDate = new DateTimeOffset(2024, 10, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureNonMatchingDate = new DateTimeOffset(2025, 11, 20, 10, 0, 0, TimeSpan.Zero); // Будущее, не январь, не 1-е var futureMatchingDate = new DateTimeOffset(2026, 1, 1, 10, 0, 0, TimeSpan.Zero); // 1 января 2026 — совпадает с ожидаемой датой var expectedDate = futureMatchingDate; // 1 января 2026 var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Annually, Name = "Ежегодно", Description = "Расписание по месяцу и дню года" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "Месяц", Description = "Месяц года" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Январь", EsppExportValue = "Январь", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } }, new EsppScheduleValDto { Order = 2, Type = new EsppSchType { Id = 2, Name = "День месяца", Description = "Число месяца" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "1", EsppExportValue = "1-е число", TypeId = 2, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureMatchingDate); // Assert Assert.Equal(expectedDate, resultFromPast); Assert.Equal(expectedDate, resultFromFutureNonMatching); Assert.Equal(expectedDate, resultFromFutureMatching); } [Fact] public async Task GetNextDate_Annually2_ReturnsSameDateForAllReferenceDates() { // Arrange var pastDate = new DateTimeOffset(2024, 10, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureNonMatchingDate = new DateTimeOffset(2026, 01, 02, 10, 0, 0, TimeSpan.Zero); // Будущее, не понедельник var futureMatchingDate = new DateTimeOffset(2026, 1, 5, 10, 0, 0, TimeSpan.Zero); // Первый понедельник января 2026 — совпадает с ожидаемой датой var expectedDate = futureMatchingDate; var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Annually2, Name = "Ежегодно-2", Description = "Расписание по порядку дня недели в месяце (например, первый понедельник января)" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "Порядок", Description = "Порядковый номер дня недели (например, первый)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Первый", EsppExportValue = "Первый", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } }, new EsppScheduleValDto { Order = 2, Type = new EsppSchType { Id = 2, Name = "День недели", Description = "День недели (например, понедельник)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Понедельник", EsppExportValue = "Понедельник", TypeId = 2, DateCreated = DateTimeOffset.UtcNow, Order = 2 } }, new EsppScheduleValDto { Order = 3, Type = new EsppSchType { Id = 3, Name = "Месяц", Description = "Месяц года (например, Января)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Января", EsppExportValue = "Января", TypeId = 3, DateCreated = DateTimeOffset.UtcNow, Order = 3 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureMatchingDate); // Assert Assert.Equal(expectedDate, resultFromPast); Assert.Equal(expectedDate, resultFromFutureNonMatching); Assert.Equal(expectedDate, resultFromFutureMatching); } [Fact] public async Task GetNextDate_Weekly_ReturnsSameDateForAllReferenceDates() { // Arrange var pastDate = new DateTimeOffset(2025, 11, 19, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureNonMatchingDate = new DateTimeOffset(2025, 11, 27, 10, 0, 0, TimeSpan.Zero); // Будущее, четверг — не понедельник var futureMatchingDate = new DateTimeOffset(2025, 12, 01, 10, 0, 0, TimeSpan.Zero); // четверг — совпадает с ожидаемой датой var expectedDate = futureMatchingDate; var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Weekly, Name = "Еженедельно", Description = "Расписание по дню недели" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "День недели", Description = "День недели" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Понедельник", EsppExportValue = "Понедельник", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureNonMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureNonMatchingDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureMatchingDate); // Assert Assert.Equal(expectedDate, resultFromPast); Assert.Equal(expectedDate, resultFromFutureNonMatching); Assert.Equal(expectedDate, resultFromFutureMatching); } [Fact] public async Task GetNextDate_Regularly_EveryDay() { // Arrange var pastDate = new DateTimeOffset(2025, 11, 20, 20, 0, 0, TimeSpan.Zero); // Прошлое время var futureDate = new DateTimeOffset(2025, 11, 30, 10, 0, 0, TimeSpan.Zero); // Будущее время var matchingDate = DateTimeOffset.UtcNow; // Совпадает время var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Regularly, Name = "Регулярно", Description = "Регулярное расписание" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "Интервал", Description = "Интервал повторения (например, Ежедневно)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Ежедневно", EsppExportValue = "Ежедневно", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFuture = await service.GetNextDateAsync(Guid.NewGuid(), futureDate); var resultFromMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate); // Assert Assert.Equal(new DateTimeOffset( DateTimeOffset.UtcNow.Year, DateTimeOffset.UtcNow.Month, DateTimeOffset.UtcNow.Day, 20, 0, 0, 0, 0, TimeSpan.Zero), resultFromPast); Assert.Equal(futureDate, resultFromFuture); Assert.Equal(matchingDate.AddDays(1), resultFromMatching); } [Fact] public async Task GetNextDate_Regularly_Every3Year() { // Arrange var pastDate = new DateTimeOffset(2020, 11, 20, 10, 0, 0, TimeSpan.Zero); // Прошлое время var futureDate = new DateTimeOffset(2026, 11, 30, 10, 0, 0, TimeSpan.Zero); // Будущее время var matchingDate = DateTimeOffset.UtcNow; // Совпадает время var failureDate = new DateTimeOffset(2027, 01, 01, 23, 59, 0, TimeSpan.Zero); // Дата с ошибкой в работе var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Regularly, Name = "Regularly", Description = "Регулярно" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "Интервал", Description = "Интервал повторения (например, Ежедневно)" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Каждые 3 года", EsppExportValue = "1095 00:00:00", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFromPast = await service.GetNextDateAsync(Guid.NewGuid(), pastDate); var resultFromFutureMatching = await service.GetNextDateAsync(Guid.NewGuid(), futureDate); var resultFromSimpleMatching = await service.GetNextDateAsync(Guid.NewGuid(), matchingDate); var resultFromFailure = await service.GetNextDateAsync(Guid.NewGuid(), failureDate); // Assert Assert.Equal(pastDate.AddHours(26280 * 2), resultFromPast); Assert.Equal(futureDate, resultFromFutureMatching); Assert.Equal(matchingDate.AddHours(26280), resultFromSimpleMatching); Assert.Equal(failureDate, resultFromFailure); } [Fact] public async Task GetNextDate_Weekly_TestUTCToMsk() { // Arrange var beforeMSKTZ = new DateTimeOffset(2025, 11, 25, 3, 0, 0, TimeSpan.Zero); var afterMSKTZ = new DateTimeOffset(2025, 12, 01, 3, 0, 0, TimeSpan.Zero); var scheduleDto = new EsppScheduleDto { TypeSchedule = new EsppSchTypeSchedule { Id = (int)EsppSchTypeScheduleEnum.Weekly, Name = "Еженедельно", Description = "Расписание по дню недели" }, Values = new List { new EsppScheduleValDto { Order = 1, Type = new EsppSchType { Id = 1, Name = "День недели", Description = "День недели" }, Value = new EsppSchTypeValue { Id = Guid.NewGuid(), Value = "Понедельник", EsppExportValue = "Понедельник", TypeId = 1, DateCreated = DateTimeOffset.UtcNow, Order = 1 } } } }; esppSchTypeConfigServiceMock .Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny())) .ReturnsAsync(scheduleDto); // Act var resultFrombeforeMSKTZ = await service.GetNextDateAsync(Guid.NewGuid(), beforeMSKTZ); var resultFromafterMSKTZ = await service.GetNextDateAsync(Guid.NewGuid(), afterMSKTZ); // Assert Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFrombeforeMSKTZ); Assert.Equal(new DateTimeOffset(2025, 12, 1, 3, 0, 0, TimeSpan.Zero), resultFromafterMSKTZ); } } }