using FluentAssertions; using foodmarket.Application.Common; using Xunit; namespace foodmarket.UnitTests; /// Нормализация даты документа к UTC и защита от «будущих» времён /// (корень бага «Последние продажи» показывали время вперёд). public class BusinessTimeTests { [Fact] public void Utc_date_in_past_is_unchanged() { var past = DateTime.UtcNow.AddHours(-3); BusinessTime.ToInstantUtc(past).Should().BeCloseTo(past, TimeSpan.FromSeconds(1)); } [Fact] public void Future_date_is_clamped_to_now() { var future = DateTime.UtcNow.AddHours(3); var result = BusinessTime.ToInstantUtc(future); result.Should().BeOnOrBefore(DateTime.UtcNow.AddSeconds(1)); result.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1), "будущее заменяется на now"); } [Fact] public void Small_clock_skew_within_tolerance_is_kept() { var slightlyAhead = DateTime.UtcNow.AddMinutes(2); BusinessTime.ToInstantUtc(slightlyAhead).Should().BeCloseTo(slightlyAhead, TimeSpan.FromSeconds(1), "небольшой разбег часов (до 5 мин) допускаем"); } [Fact] public void Local_kind_is_converted_to_utc() { var local = DateTime.SpecifyKind(DateTime.Now.AddHours(-1), DateTimeKind.Local); var result = BusinessTime.ToInstantUtc(local); result.Kind.Should().Be(DateTimeKind.Utc); result.Should().BeCloseTo(local.ToUniversalTime(), TimeSpan.FromSeconds(1)); } [Fact] public void Unspecified_kind_is_treated_as_utc_no_shift() { var naive = DateTime.SpecifyKind(DateTime.UtcNow.AddHours(-2), DateTimeKind.Unspecified); var result = BusinessTime.ToInstantUtc(naive); result.Kind.Should().Be(DateTimeKind.Utc); result.Should().BeCloseTo(DateTime.SpecifyKind(naive, DateTimeKind.Utc), TimeSpan.FromSeconds(1)); } }