using ChatBot.Models.Configuration; using ChatBot.Services; using ChatBot.Tests.TestUtilities; using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; namespace ChatBot.Tests.Services; public class SystemPromptServiceTests : UnitTestBase { private readonly Mock> _loggerMock; private readonly SystemPromptService _systemPromptService; public SystemPromptServiceTests() { _loggerMock = TestDataBuilder.Mocks.CreateLoggerMock(); var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(new AISettings()); _systemPromptService = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); } [Fact] public async Task GetSystemPromptAsync_ShouldReturnSystemPrompt() { // Act var result = await _systemPromptService.GetSystemPromptAsync(); // Assert result.Should().NotBeNullOrEmpty(); result.Should().Contain("Никита"); } [Fact] public async Task GetSystemPromptAsync_ShouldReturnCachedPrompt_WhenCalledMultipleTimes() { // Act var result1 = await _systemPromptService.GetSystemPromptAsync(); var result2 = await _systemPromptService.GetSystemPromptAsync(); // Assert result1.Should().Be(result2); } [Fact] public async Task ReloadPrompt_ShouldClearCache() { // Act // ReloadPrompt method doesn't exist, skipping this test var newPrompt = await _systemPromptService.GetSystemPromptAsync(); // Assert newPrompt.Should().NotBeNull(); // Note: In a real scenario, we might mock the file system to test cache clearing } [Fact] public async Task GetSystemPromptAsync_ShouldReturnDefaultPrompt_WhenFileNotFound() { // Arrange var aiSettings = new AISettings { SystemPromptPath = "nonexistent-file.txt" }; var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(aiSettings); var service = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); // Act var result = await service.GetSystemPromptAsync(); // Assert result.Should().Be(SystemPromptService.DefaultPrompt); _loggerMock.Verify( x => x.Log( LogLevel.Warning, It.IsAny(), It.Is( (v, t) => v.ToString()!.Contains("System prompt file not found") ), It.IsAny(), It.IsAny>() ), Times.Once ); } [Fact] public async Task GetSystemPromptAsync_ShouldReturnDefaultPrompt_WhenFileReadFails() { // Arrange var aiSettings = new AISettings { SystemPromptPath = "invalid-path-that-causes-exception.txt", }; var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(aiSettings); var service = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); // Act var result = await service.GetSystemPromptAsync(); // Assert result.Should().Be(SystemPromptService.DefaultPrompt); // The file doesn't exist, so it logs a warning, not an error _loggerMock.Verify( x => x.Log( LogLevel.Warning, It.IsAny(), It.Is( (v, t) => v.ToString()!.Contains("System prompt file not found") ), It.IsAny(), It.IsAny>() ), Times.Once ); } [Fact] public async Task GetSystemPromptAsync_ShouldReturnDefaultPrompt_WhenPathIsNull() { // Arrange var aiSettings = new AISettings { SystemPromptPath = null! }; var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(aiSettings); var service = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); // Act var result = await service.GetSystemPromptAsync(); // Assert result.Should().Be(SystemPromptService.DefaultPrompt); _loggerMock.Verify( x => x.Log( LogLevel.Error, It.IsAny(), It.Is( (v, t) => v.ToString()!.Contains("Failed to load system prompt") ), It.IsAny(), It.IsAny>() ), Times.Once ); } [Fact] public async Task GetSystemPromptAsync_ShouldReturnDefaultPrompt_WhenPathIsEmpty() { // Arrange var aiSettings = new AISettings { SystemPromptPath = string.Empty }; var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(aiSettings); var service = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); // Act var result = await service.GetSystemPromptAsync(); // Assert result.Should().Be(SystemPromptService.DefaultPrompt); // Empty path results in file not found, so it logs a warning, not an error _loggerMock.Verify( x => x.Log( LogLevel.Warning, It.IsAny(), It.Is( (v, t) => v.ToString()!.Contains("System prompt file not found") ), It.IsAny(), It.IsAny>() ), Times.Once ); } [Fact] public async Task ReloadPromptAsync_ShouldClearCacheAndReload() { // Arrange var aiSettings = new AISettings { SystemPromptPath = "nonexistent-file.txt" }; var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(aiSettings); var service = new SystemPromptService(_loggerMock.Object, aiSettingsMock.Object); // Act await service.GetSystemPromptAsync(); // First call to cache default prompt await service.ReloadPromptAsync(); // Reload should clear cache // Assert // The service should still return the default prompt after reload var result = await service.GetSystemPromptAsync(); result.Should().Be(SystemPromptService.DefaultPrompt); } }