using GmRelay.Bot.Features.Sessions.RescheduleSession; namespace GmRelay.Bot.Tests.Features.Sessions.RescheduleSession; public sealed class HandleRescheduleTimeInputHandlerTests { [Fact] public void TryParseVotingInput_ShouldAcceptTwoOptionsAndDeadline() { var now = new DateTimeOffset(2026, 4, 24, 8, 0, 0, TimeSpan.Zero); var ok = RescheduleVotingInput.TryParse( """ 25.04.2026 19:30 26.04.2026 18:00 Дедлайн: 25.04.2026 12:00 """, now, out var input, out var error); Assert.True(ok, error); Assert.Equal(2, input.Options.Count); Assert.Equal(new DateTimeOffset(2026, 4, 25, 16, 30, 0, TimeSpan.Zero), input.Options[0]); Assert.Equal(new DateTimeOffset(2026, 4, 26, 15, 0, 0, TimeSpan.Zero), input.Options[1]); Assert.Equal(new DateTimeOffset(2026, 4, 25, 9, 0, 0, TimeSpan.Zero), input.Deadline); } [Fact] public void TryParseVotingInput_ShouldRejectSingleOption() { var now = new DateTimeOffset(2026, 4, 24, 8, 0, 0, TimeSpan.Zero); var ok = RescheduleVotingInput.TryParse( """ 25.04.2026 19:30 Дедлайн: 25.04.2026 12:00 """, now, out _, out var error); Assert.False(ok); Assert.Equal("Укажите от 2 до 3 вариантов времени.", error); } [Fact] public void BuildVotingMessage_ShouldShowOptionsDeadlineVotesAndPendingParticipants() { var firstOptionId = Guid.NewGuid(); var secondOptionId = Guid.NewGuid(); var aliceId = Guid.NewGuid(); var bobId = Guid.NewGuid(); var charlieId = Guid.NewGuid(); var currentTime = new DateTime(2026, 4, 25, 16, 30, 0, DateTimeKind.Utc); var deadline = new DateTimeOffset(2026, 4, 25, 9, 0, 0, TimeSpan.Zero); var options = new List { new(firstOptionId, 1, new DateTimeOffset(2026, 4, 26, 16, 0, 0, TimeSpan.Zero)), new(secondOptionId, 2, new DateTimeOffset(2026, 4, 27, 17, 0, 0, TimeSpan.Zero)) }; var participants = new List { new(aliceId, "Alice", "alice"), new(bobId, "Bob", null), new(charlieId, "Charlie", null) }; var votes = new List { new(firstOptionId, aliceId, "Alice", "alice"), new(secondOptionId, bobId, "Bob", null) }; var text = HandleRescheduleTimeInputHandler.BuildVotingMessage( "Shadowrun", currentTime, deadline, options, participants, votes); Assert.Contains("Shadowrun", text); Assert.Contains("Дедлайн: 25 апреля 2026, 12:00 (МСК)", text); Assert.Contains("1. 26 апреля 2026, 19:00 (МСК) — 1 голос", text); Assert.Contains("@alice", text); Assert.Contains("2. 27 апреля 2026, 20:00 (МСК) — 1 голос", text); Assert.Contains("Bob", text); Assert.Contains("Не проголосовали: Charlie", text); Assert.Contains("Голосов: 2/3", text); } [Fact] public void BuildVotingKeyboard_ShouldCreateOneButtonPerOption() { var firstOptionId = Guid.NewGuid(); var secondOptionId = Guid.NewGuid(); var options = new List { new(firstOptionId, 1, new DateTimeOffset(2026, 4, 26, 16, 0, 0, TimeSpan.Zero)), new(secondOptionId, 2, new DateTimeOffset(2026, 4, 27, 17, 0, 0, TimeSpan.Zero)) }; var keyboard = HandleRescheduleTimeInputHandler.BuildVotingKeyboard(options); var buttons = keyboard.InlineKeyboard.SelectMany(row => row).ToList(); Assert.Collection( buttons, button => { Assert.Equal("1. 26.04 19:00", button.Text); Assert.Equal($"reschedule_vote:{firstOptionId}", button.CallbackData); }, button => { Assert.Equal("2. 27.04 20:00", button.Text); Assert.Equal($"reschedule_vote:{secondOptionId}", button.CallbackData); }); } }