add more tests
Some checks failed
SonarQube / Build and analyze (push) Failing after 2m56s
Unit Tests / Run Tests (push) Failing after 2m28s

This commit is contained in:
Leonid Pershin
2025-10-20 07:02:12 +03:00
parent af9773e7d6
commit 1647fe19d3
12 changed files with 3714 additions and 21 deletions

View File

@@ -0,0 +1,380 @@
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<ChatService> _chatServiceMock;
private readonly Mock<ModelService> _modelServiceMock;
private readonly TestTelegramCommand _testCommand;
public TelegramCommandBaseTests()
{
_chatServiceMock = new Mock<ChatService>(
TestDataBuilder.Mocks.CreateLoggerMock<ChatService>().Object,
TestDataBuilder.Mocks.CreateAIServiceMock().Object,
TestDataBuilder.Mocks.CreateSessionStorageMock().Object,
TestDataBuilder
.Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings())
.Object,
TestDataBuilder.Mocks.CreateCompressionServiceMock().Object
);
_modelServiceMock = new Mock<ModelService>(
TestDataBuilder.Mocks.CreateLoggerMock<ModelService>().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<NullReferenceException>(); // 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
}
}
/// <summary>
/// Test implementation of TelegramCommandBase for testing purposes
/// </summary>
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<string> 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;
}

View File

@@ -0,0 +1,491 @@
using ChatBot.Services;
using ChatBot.Services.Telegram.Commands;
using ChatBot.Services.Telegram.Interfaces;
using ChatBot.Services.Telegram.Services;
using ChatBot.Tests.TestUtilities;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using Telegram.Bot.Types;
namespace ChatBot.Tests.Telegram.Commands;
public class TelegramCommandProcessorTests : UnitTestBase
{
private readonly CommandRegistry _commandRegistry;
private readonly ChatService _chatService;
private readonly Mock<ILogger<TelegramCommandProcessor>> _loggerMock;
private readonly BotInfoService _botInfoService;
private readonly TelegramCommandProcessor _processor;
public TelegramCommandProcessorTests()
{
_commandRegistry = new CommandRegistry(
TestDataBuilder.Mocks.CreateLoggerMock<CommandRegistry>().Object,
Enumerable.Empty<ITelegramCommand>()
);
_chatService = new ChatService(
TestDataBuilder.Mocks.CreateLoggerMock<ChatService>().Object,
TestDataBuilder.Mocks.CreateAIServiceMock().Object,
TestDataBuilder.Mocks.CreateSessionStorageMock().Object,
TestDataBuilder
.Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings())
.Object,
TestDataBuilder.Mocks.CreateCompressionServiceMock().Object
);
_loggerMock = TestDataBuilder.Mocks.CreateLoggerMock<TelegramCommandProcessor>();
_botInfoService = new BotInfoService(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
_processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
_botInfoService
);
}
[Fact]
public void Constructor_ShouldInitializeServices()
{
// Arrange & Act
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
_botInfoService
);
// Assert
processor.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldProcessAsRegularMessage_WhenNoCommandFound()
{
// Arrange
var messageText = "Hello bot";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
result.Should().NotBeEmpty();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleEmptyMessage()
{
// Arrange
var messageText = "";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleVeryLongMessage()
{
// Arrange
var messageText = new string('A', 10000);
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleEmptyUsername()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = "";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleEmptyChatType()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = "testuser";
var chatType = "";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleEmptyChatTitle()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNegativeChatId()
{
// Arrange
var messageText = "Hello";
var chatId = -12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleZeroChatId()
{
// Arrange
var messageText = "Hello";
var chatId = 0L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleVeryLongUsername()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = new string('A', 1000);
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleSpecialCharactersInMessage()
{
// Arrange
var messageText = "Hello! @#$%^&*()_+-=[]{}|;':\",./<>?";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleUnicodeCharacters()
{
// Arrange
var messageText = "Привет! 🌍 Hello!";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNullMessage()
{
// Arrange
string messageText = null!;
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNullUsername()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
string username = null!;
var chatType = "private";
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNullChatType()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = "testuser";
string chatType = null!;
var chatTitle = "Test Chat";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNullChatTitle()
{
// Arrange
var messageText = "Hello";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
string chatTitle = null!;
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleCancellationToken()
{
// Arrange
var messageText = "Hello bot";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
var cts = new CancellationTokenSource();
cts.Cancel();
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle,
cancellationToken: cts.Token
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleReplyInfo()
{
// Arrange
var messageText = "Hello bot";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
var replyInfo = new ReplyInfo
{
MessageId = 1,
UserId = 123,
Username = "testuser",
};
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle,
replyInfo
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_ShouldHandleNullReplyInfo()
{
// Arrange
var messageText = "Hello bot";
var chatId = 12345L;
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
ReplyInfo? replyInfo = null;
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle,
replyInfo
);
// Assert
result.Should().NotBeNull();
}
}