using ChatBot.Services; using ChatBot.Services.Telegram.Commands; using ChatBot.Tests.TestUtilities; using FluentAssertions; using Moq; namespace ChatBot.Tests.Telegram.Commands; public class TelegramCommandBaseTests : UnitTestBase { private readonly Mock _chatServiceMock; private readonly Mock _modelServiceMock; private readonly TestTelegramCommand _testCommand; public TelegramCommandBaseTests() { _chatServiceMock = new Mock( TestDataBuilder.Mocks.CreateLoggerMock().Object, TestDataBuilder.Mocks.CreateAIServiceMock().Object, TestDataBuilder.Mocks.CreateSessionStorageMock().Object, TestDataBuilder .Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings()) .Object, TestDataBuilder.Mocks.CreateCompressionServiceMock().Object ); _modelServiceMock = new Mock( TestDataBuilder.Mocks.CreateLoggerMock().Object, TestDataBuilder .Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateOllamaSettings()) .Object ); _testCommand = new TestTelegramCommand(_chatServiceMock.Object, _modelServiceMock.Object); } [Fact] public void Constructor_ShouldInitializeServices() { // Arrange & Act var command = new TestTelegramCommand(_chatServiceMock.Object, _modelServiceMock.Object); // Assert command.Should().NotBeNull(); command.ChatService.Should().Be(_chatServiceMock.Object); command.ModelService.Should().Be(_modelServiceMock.Object); } [Fact] public void CommandName_ShouldReturnCorrectName() { // Act var commandName = _testCommand.CommandName; // Assert commandName.Should().Be("/test"); } [Fact] public void Description_ShouldReturnCorrectDescription() { // Act var description = _testCommand.Description; // Assert description.Should().Be("Test command"); } [Theory] [InlineData("/test", true)] [InlineData("/TEST", true)] [InlineData("/Test", true)] [InlineData("/test ", true)] [InlineData("/test arg1 arg2", true)] [InlineData("/test@botname", true)] [InlineData("/test@botname arg1", true)] [InlineData("/other", false)] [InlineData("test", false)] [InlineData("", false)] [InlineData(" ", false)] public void CanHandle_ShouldReturnCorrectResult(string messageText, bool expected) { // Act var result = _testCommand.CanHandle(messageText); // Assert result.Should().Be(expected); } [Theory] [InlineData("/test@mybot")] [InlineData("/test@botname")] [InlineData("/test@")] [InlineData("/test@verylongbotname")] public void CanHandle_ShouldRemoveBotUsername(string messageText) { // Act var result = _testCommand.CanHandle(messageText); // Assert result.Should().BeTrue(); // The command should be extracted correctly without @botname } [Fact] public void CanHandle_ShouldHandleNullMessage() { // Act & Assert var act = () => _testCommand.CanHandle(null!); act.Should().Throw(); // The method throws NullReferenceException, not ArgumentNullException } [Fact] public void HasArguments_ShouldReturnTrue_WhenArgumentsExist() { // Arrange var context = new TelegramCommandContext { Arguments = "arg1 arg2" }; // Act var result = TestTelegramCommand.HasArguments(context); // Assert result.Should().BeTrue(); } [Theory] [InlineData("")] [InlineData(" ")] [InlineData("\t")] [InlineData("\n")] [InlineData("\r\n")] public void HasArguments_ShouldReturnFalse_WhenArgumentsAreEmptyOrWhitespace(string arguments) { // Arrange var context = new TelegramCommandContext { Arguments = arguments }; // Act var result = TestTelegramCommand.HasArguments(context); // Assert result.Should().BeFalse(); } [Fact] public void HasArguments_ShouldReturnFalse_WhenArgumentsAreNull() { // Arrange var context = new TelegramCommandContext { Arguments = null! }; // Act var result = TestTelegramCommand.HasArguments(context); // Assert result.Should().BeFalse(); } [Fact] public void GetArguments_ShouldReturnCorrectArguments() { // Arrange var expectedArguments = "arg1 arg2 arg3"; var context = new TelegramCommandContext { Arguments = expectedArguments }; // Act var result = TestTelegramCommand.GetArguments(context); // Assert result.Should().Be(expectedArguments); } [Fact] public void GetArguments_ShouldReturnEmptyString_WhenArgumentsAreNull() { // Arrange var context = new TelegramCommandContext { Arguments = null! }; // Act var result = TestTelegramCommand.GetArguments(context); // Assert result.Should().BeNull(); // The method returns null when Arguments is null } [Fact] public void GetArguments_ShouldReturnEmptyString_WhenArgumentsAreEmpty() { // Arrange var context = new TelegramCommandContext { Arguments = "" }; // Act var result = TestTelegramCommand.GetArguments(context); // Assert result.Should().BeEmpty(); } [Fact] public async Task ExecuteAsync_ShouldBeImplementedByDerivedClass() { // Arrange var context = new TelegramCommandContext { ChatId = 12345, Username = "testuser", MessageText = "/test", ChatType = "private", ChatTitle = "Test Chat", }; // Act var result = await _testCommand.ExecuteAsync(context); // Assert result.Should().Be("Test command executed"); } [Fact] public void CanHandle_ShouldHandleVeryLongMessage() { // Arrange var longMessage = "/test " + new string('a', 10000); // Act var result = _testCommand.CanHandle(longMessage); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithSpecialCharacters() { // Arrange var messageWithSpecialChars = "/test !@#$%^&*()_+-=[]{}|;':\",./<>?"; // Act var result = _testCommand.CanHandle(messageWithSpecialChars); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithUnicodeCharacters() { // Arrange var messageWithUnicode = "/test привет мир 🌍"; // Act var result = _testCommand.CanHandle(messageWithUnicode); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithMultipleSpaces() { // Arrange var messageWithMultipleSpaces = "/test arg1 arg2"; // Act var result = _testCommand.CanHandle(messageWithMultipleSpaces); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithTabsAndNewlines() { // Arrange var messageWithWhitespace = "/test arg1 arg2 arg3"; // Use spaces instead of tabs/newlines // Act var result = _testCommand.CanHandle(messageWithWhitespace); // Assert result.Should().BeTrue(); // The method should handle spaces in arguments } [Fact] public void CanHandle_ShouldHandleMessageWithOnlyCommand() { // Arrange var messageWithOnlyCommand = "/test"; // Act var result = _testCommand.CanHandle(messageWithOnlyCommand); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithTrailingSpaces() { // Arrange var messageWithTrailingSpaces = "/test "; // Act var result = _testCommand.CanHandle(messageWithTrailingSpaces); // Assert result.Should().BeTrue(); } [Fact] public void CanHandle_ShouldHandleMessageWithLeadingSpaces() { // Arrange var messageWithLeadingSpaces = " /test"; // Act var result = _testCommand.CanHandle(messageWithLeadingSpaces); // Assert result.Should().BeFalse(); // Leading spaces should make it not match } [Fact] public void CanHandle_ShouldHandleMessageWithMultipleAtSymbols() { // Arrange var messageWithMultipleAt = "/test@bot1@bot2"; // Act var result = _testCommand.CanHandle(messageWithMultipleAt); // Assert result.Should().BeTrue(); // Should handle multiple @ symbols } [Fact] public void CanHandle_ShouldHandleMessageWithAtSymbolButNoBotName() { // Arrange var messageWithAtOnly = "/test@"; // Act var result = _testCommand.CanHandle(messageWithAtOnly); // Assert result.Should().BeTrue(); // Should handle @ without bot name } } /// /// Test implementation of TelegramCommandBase for testing purposes /// public class TestTelegramCommand : TelegramCommandBase { public TestTelegramCommand(ChatService chatService, ModelService modelService) : base(chatService, modelService) { } public override string CommandName => "/test"; public override string Description => "Test command"; public override Task ExecuteAsync( TelegramCommandContext context, CancellationToken cancellationToken = default ) { return Task.FromResult("Test command executed"); } // Expose protected methods for testing public new static bool HasArguments(TelegramCommandContext context) { return TelegramCommandBase.HasArguments(context); } public static new string GetArguments(TelegramCommandContext context) { return TelegramCommandBase.GetArguments(context); } // Expose protected fields for testing public ChatService ChatService => _chatService; public ModelService ModelService => _modelService; }