Files
parr_api/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs

615 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Logging;
using Moq;
using PARR.DAL.Contracts;
using PARR.DAL.DomainModels;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.TransformServices;
namespace PARR.DAL.Tests.TransformServices
{
public class EsppScheduleTransformServiceTests
{
private Mock<IEsppSchTypeConfigService> esppSchTypeConfigServiceMock;
private Mock<INextRunModifierService> nextRunModifierServiceMock;
private ILogger<EsppScheduleTransformService> logger;
private EsppScheduleTransformService service;
public EsppScheduleTransformServiceTests()
{
esppSchTypeConfigServiceMock = new Mock<IEsppSchTypeConfigService>();
nextRunModifierServiceMock = new Mock<INextRunModifierService>();
var loggerFactory = new LoggerFactory();
logger = loggerFactory.CreateLogger<EsppScheduleTransformService>();
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<EsppScheduleValDto>
{
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<Guid>()))
.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<EsppScheduleValDto>
{
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<Guid>()))
.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<EsppScheduleValDto>
{
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<Guid>()))
.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<EsppScheduleValDto>
{
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<Guid>()))
.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<EsppScheduleValDto>
{
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<Guid>()))
.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, 10, 0, 0, TimeSpan.Zero); // Прошлое время
var futureNonMatchingDate = new DateTimeOffset(2025, 11, 27, 10, 0, 0, TimeSpan.Zero); // Будущее время
var matchingDate = new DateTimeOffset(2025, 11, 26, 10, 0, 0, TimeSpan.Zero); // Совпадает время
var scheduleDto = new EsppScheduleDto
{
TypeSchedule = new EsppSchTypeSchedule
{
Id = (int)EsppSchTypeScheduleEnum.Regularly,
Name = "Регулярно",
Description = "Регулярное расписание"
},
Values = new List<EsppScheduleValDto>
{
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<Guid>()))
.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(), matchingDate);
// Assert
Assert.Equal(matchingDate.AddDays(1), resultFromPast);
Assert.Equal(futureNonMatchingDate.AddDays(1), resultFromFutureNonMatching);
Assert.Equal(matchingDate.AddDays(1), resultFromFutureMatching);
}
/*
/// <summary>
/// дата в будущем, но не по расписанию
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetNextDate_Weekly_FutureDateNotMatchingSchedule_ReturnsNextScheduledDate()
{
// Arrange
var futureDate = new DateTimeOffset(2025, 12, 04, 10, 0, 0, TimeSpan.Zero); // Четверг
var scheduleDto = new EsppScheduleDto
{
TypeSchedule = new EsppSchTypeSchedule
{
Id = (int)EsppSchTypeScheduleEnum.Weekly,
Name = "Еженедельно",
Description = "Расписание по дню недели"
},
Values = new List<EsppScheduleValDto>
{
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<Guid>()))
.ReturnsAsync(scheduleDto);
// Act
var result = await service.GetNextDateAsync(Guid.NewGuid(), futureDate);
// Assert
Assert.Equal(DayOfWeek.Monday, result.DayOfWeek);
Assert.True(result >= DateTimeOffset.UtcNow, "Дата должна быть в будущем");
}
/// <summary>
/// несуществующая дата (31 февраля)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetNextDate_Monthly_InvalidDay_FallsBackToLastDay()
{
// Arrange
var pastDate = new DateTimeOffset(2025, 1, 10, 10, 0, 0, TimeSpan.Zero); // Прошлое
var scheduleDto = new EsppScheduleDto
{
TypeSchedule = new EsppSchTypeSchedule
{
Id = (int)EsppSchTypeScheduleEnum.Monthly,
Name = "Ежемесячно",
Description = "Расписание по числу месяца"
},
Values = new List<EsppScheduleValDto>
{
new EsppScheduleValDto
{
Order = 1,
Type = new EsppSchType
{
Id = 1,
Name = "День месяца",
Description = "Число месяца"
},
Value = new EsppSchTypeValue
{
Id = Guid.NewGuid(),
Value = "31", // <-- 31 февраля не существует
EsppExportValue = "31-е число",
TypeId = 1,
DateCreated = DateTimeOffset.UtcNow,
Order = 1
}
}
}
};
esppSchTypeConfigServiceMock
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
.ReturnsAsync(scheduleDto);
// Act
var result = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
// Assert
// Результат должен быть 28 февраля (или 29 в високосный год)
Assert.Equal(28, result.Day); // или 29, если високосный
Assert.Equal(2, result.Month);
}
/// <summary>
/// корректная рекурсия (без зацикливания)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetNextDate_Regularly_RecursionDoesNotLoop()
{
// Arrange
var pastDate = new DateTimeOffset(1925, 11, 20, 10, 0, 0, TimeSpan.Zero); // Давно прошло
var scheduleDto = new EsppScheduleDto
{
TypeSchedule = new EsppSchTypeSchedule
{
Id = (int)EsppSchTypeScheduleEnum.Regularly,
Name = "Регулярно",
Description = "Регулярное расписание"
},
Values = new List<EsppScheduleValDto>
{
new EsppScheduleValDto
{
Order = 1,
Type = new EsppSchType
{
Id = 1,
Name = "Интервал",
Description = "Интервал повторения (например, Ежедневно)"
},
Value = new EsppSchTypeValue
{
Id = Guid.NewGuid(),
Value = "Каждые 2 часа", // <-- Интервал 2 часа
EsppExportValue = "Каждые 2 часа",
TypeId = 1,
DateCreated = DateTimeOffset.UtcNow,
Order = 1
}
}
}
};
esppSchTypeConfigServiceMock
.Setup(x => x.GetEsppScheduleDtoAsync(It.IsAny<Guid>()))
.ReturnsAsync(scheduleDto);
// Act
var result = await service.GetNextDateAsync(Guid.NewGuid(), pastDate);
// Assert
// Результат должен быть >= DateTimeOffset.UtcNow
Assert.True(result >= DateTimeOffset.UtcNow, "Дата должна быть в будущем");
// Должно быть кратно интервалу
var diff = (result - pastDate).TotalHours;
Assert.True(diff % 2 == 0 || diff % 2 == 2, "Разница должна быть кратна 2 часам");
}*/
}
}