using GmRelay.Bot.Features.Sessions.CreateSession.Wizard; using Telegram.Bot.Types; using Xunit; namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard; /// /// Verifies the Telegram UpdateWizardInteraction mapping /// that exposes. The mapper is the /// single bridge between Telegram's native update type and the /// platform-neutral wizard core, so its contract needs to be locked /// down: callback queries carry the data payload, text messages carry /// their text, and photos carry the largest photo's FileId. /// public sealed class WizardInteractionMapperTests { [Fact] public void CallbackUpdate_ProducesCallbackInteraction_WithPayloadAndOwner() { var update = new Update { CallbackQuery = new CallbackQuery { Id = "cb-42", Data = "wizard:choice:Type:single", From = new User { Id = 100, FirstName = "GM" }, Message = new Message { Chat = new Chat { Id = 42 } }, }, }; var ok = WizardInteractionMapper.TryMap(update, out var interaction); Assert.True(ok); Assert.Equal("100", interaction.OwnerId); Assert.Null(interaction.Text); Assert.Equal("wizard:choice:Type:single", interaction.CallbackPayload); Assert.Null(interaction.PhotoFileId); Assert.Null(interaction.PhotoUrl); Assert.Equal("cb-42", interaction.InteractionId); } [Fact] public void TextUpdate_ProducesTextInteraction_WithTextAndNoCallback() { var update = new Update { Message = new Message { Text = "My Game Title", Chat = new Chat { Id = 42 }, From = new User { Id = 200, FirstName = "GM" }, }, }; var ok = WizardInteractionMapper.TryMap(update, out var interaction); Assert.True(ok); Assert.Equal("200", interaction.OwnerId); Assert.Equal("My Game Title", interaction.Text); Assert.Null(interaction.CallbackPayload); Assert.Null(interaction.PhotoFileId); Assert.Equal("msg", interaction.InteractionId); } [Fact] public void PhotoUpdate_ProducesPhotoInteraction_WithLargestFileId() { var update = new Update { Message = new Message { Chat = new Chat { Id = 42 }, From = new User { Id = 300, FirstName = "GM" }, Photo = new[] { new PhotoSize { FileId = "small-id", Width = 90, Height = 60 }, new PhotoSize { FileId = "medium-id", Width = 320, Height = 240 }, new PhotoSize { FileId = "large-id", Width = 800, Height = 600 }, }, }, }; var ok = WizardInteractionMapper.TryMap(update, out var interaction); Assert.True(ok); Assert.Equal("300", interaction.OwnerId); Assert.Null(interaction.Text); Assert.Null(interaction.CallbackPayload); Assert.Equal("large-id", interaction.PhotoFileId); } [Fact] public void CaptionedPhoto_ProducesPhotoInteraction_AndKeepsCaptionOutOfText() { // Telegram sometimes attaches a caption to a photo message. The // mapper treats it as a non-text interaction (cover-step uses // PhotoFileId, not caption). This test pins that distinction. var update = new Update { Message = new Message { Caption = "ignored", Chat = new Chat { Id = 42 }, From = new User { Id = 400 }, Photo = new[] { new PhotoSize { FileId = "only-id", Width = 100, Height = 100 }, }, }, }; var ok = WizardInteractionMapper.TryMap(update, out var interaction); Assert.True(ok); Assert.Equal("only-id", interaction.PhotoFileId); } [Fact] public void EmptyUpdate_ReturnsFalse() { var ok = WizardInteractionMapper.TryMap(new Update(), out var interaction); Assert.False(ok); Assert.Null(interaction); } }