From 94b31b6056469b7fc4add6ff2eab58e6433a09a0 Mon Sep 17 00:00:00 2001 From: HueByte Date: Mon, 23 Feb 2026 15:52:18 +0100 Subject: [PATCH] refactor: replace FakeChatService with FakeUserService for user authentication and profile handling in tests --- .../Irc/IrcCommandHandlerTests.cs | 20 ++++---- src/EchoHub.Tests/Irc/TestHelpers.cs | 48 +++++++++++++++---- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/EchoHub.Tests/Irc/IrcCommandHandlerTests.cs b/src/EchoHub.Tests/Irc/IrcCommandHandlerTests.cs index 9aed298..35c45f8 100644 --- a/src/EchoHub.Tests/Irc/IrcCommandHandlerTests.cs +++ b/src/EchoHub.Tests/Irc/IrcCommandHandlerTests.cs @@ -12,11 +12,12 @@ public class IrcCommandHandlerTests { private readonly IrcOptions _options = new() { ServerName = "testserver", Motd = null }; private readonly FakeChatService _chatService = new(); + private readonly FakeUserService _userService = new(); private readonly FakeChannelService _channelService = new(); private readonly FakeEncryptionService _encryption = new(); private IrcCommandHandler CreateHandler(IrcClientConnection conn) => - new(conn, _options, _chatService, _channelService, _encryption, NullLogger.Instance); + new(conn, _options, _chatService, _userService, _channelService, _encryption, NullLogger.Instance); private async Task> RunAndCapture(string[] inputLines, Action? setup = null) @@ -85,7 +86,7 @@ public class IrcCommandHandlerTests public async Task PassNickUser_ValidCredentials_Registers() { var userId = Guid.NewGuid(); - _chatService.AuthResult = (userId, "alice"); + _userService.AuthResult = FakeUserService.SuccessResult(userId, "alice"); var lines = await RunAndCapture([ "PASS secret123", @@ -112,7 +113,7 @@ public class IrcCommandHandlerTests [Fact] public async Task PassNickUser_WrongPassword_GetsAuthError() { - _chatService.AuthResult = null; + _userService.AuthResult = null; var lines = await RunAndCapture([ "PASS wrongpassword", @@ -120,7 +121,8 @@ public class IrcCommandHandlerTests "USER alice 0 * :Alice Smith" ]); - Assert.Contains(lines, l => l.Contains("464") && l.Contains("incorrect")); + Assert.Contains(lines, l => l.Contains("464")); + Assert.Contains(lines, l => l.Contains("ERROR") && l.Contains("Authentication failed")); } [Fact] @@ -189,7 +191,7 @@ public class IrcCommandHandlerTests public async Task SaslPlain_ValidCredentials_Authenticates() { var userId = Guid.NewGuid(); - _chatService.AuthResult = (userId, "alice"); + _userService.AuthResult = FakeUserService.SuccessResult(userId, "alice"); var saslPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes("\0alice\0password123")); @@ -210,7 +212,7 @@ public class IrcCommandHandlerTests [Fact] public async Task SaslPlain_InvalidCredentials_GetsError() { - _chatService.AuthResult = null; + _userService.AuthResult = null; var saslPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes("\0alice\0wrongpwd")); @@ -478,7 +480,7 @@ public class IrcCommandHandlerTests [Fact] public async Task Whois_ExistingUser_ReturnsInfo() { - _chatService.ProfileToReturn = new UserProfileDto( + _userService.ProfileToReturn = new UserProfileDto( Guid.NewGuid(), "bob", "Bob S.", "Hello!", null, null, UserStatus.Online, null, ServerRole.Member, DateTimeOffset.UtcNow.AddDays(-30), DateTimeOffset.UtcNow); @@ -496,7 +498,7 @@ public class IrcCommandHandlerTests [Fact] public async Task Whois_NonexistentUser_GetsNoSuchNickError() { - _chatService.ProfileToReturn = null; + _userService.ProfileToReturn = null; var lines = await RunAuthenticated(["WHOIS ghost"]); @@ -506,7 +508,7 @@ public class IrcCommandHandlerTests [Fact] public async Task Whois_AwayUser_ShowsAwayMessage() { - _chatService.ProfileToReturn = new UserProfileDto( + _userService.ProfileToReturn = new UserProfileDto( Guid.NewGuid(), "bob", null, null, null, null, UserStatus.Away, "Gone fishing", ServerRole.Member, DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow); diff --git a/src/EchoHub.Tests/Irc/TestHelpers.cs b/src/EchoHub.Tests/Irc/TestHelpers.cs index 86001d2..358dec2 100644 --- a/src/EchoHub.Tests/Irc/TestHelpers.cs +++ b/src/EchoHub.Tests/Irc/TestHelpers.cs @@ -156,8 +156,6 @@ internal sealed class FakeChatService : IChatService public List HistoryToReturn { get; set; } = []; public string? JoinError { get; set; } public string? SendMessageError { get; set; } - public (Guid UserId, string Username)? AuthResult { get; set; } - public UserProfileDto? ProfileToReturn { get; set; } public List ChannelsForUserToReturn { get; set; } = []; public List OnlineUsersToReturn { get; set; } = []; @@ -210,14 +208,8 @@ internal sealed class FakeChatService : IChatService public Task BroadcastChannelUpdatedAsync(ChannelDto channel, string? channelName = null) => Task.CompletedTask; - public Task GetUserProfileAsync(string username) => - Task.FromResult(ProfileToReturn); - public Task> GetChannelsForUserAsync(string username) => Task.FromResult(ChannelsForUserToReturn); - - public Task<(Guid UserId, string Username)?> AuthenticateUserAsync(string username, string password) => - Task.FromResult(AuthResult); } /// @@ -258,3 +250,43 @@ internal sealed class FakeChannelService : IChannelService public Task<(bool Success, string? Error)> EnsureChannelMembershipAsync(Guid userId, string channelName) => Task.FromResult(MembershipResult); } + +/// +/// Fake user service that records method calls and returns pre-configured results. +/// +internal sealed class FakeUserService : IUserService +{ + // Configurable results + public UserOperationResult? AuthResult { get; set; } + public UserOperationResult? RegisterResult { get; set; } + public UserProfileDto? ProfileToReturn { get; set; } + + /// + /// Helper to create a success result from a simple userId + username pair. + /// + public static UserOperationResult SuccessResult(Guid userId, string username) => + UserOperationResult.Success(new UserProfileDto( + userId, username, null, null, null, null, + UserStatus.Online, null, ServerRole.Member, + DateTimeOffset.UtcNow, DateTimeOffset.UtcNow)); + + public Task AuthenticateUserAsync(string username, string password) => + Task.FromResult(AuthResult + ?? UserOperationResult.Fail(UserError.InvalidCredentials, "Invalid username or password.")); + + public Task RegisterUserAsync(string username, string password, string? displayName = null) => + Task.FromResult(RegisterResult + ?? UserOperationResult.Fail(UserError.AlreadyExists, "Username is already taken.")); + + public Task GetUserProfileAsync(string username) => + Task.FromResult(ProfileToReturn); + + public Task GetUserByIdAsync(Guid userId) => + Task.FromResult(ProfileToReturn); + + public Task UpdateProfileAsync(Guid userId, string? displayName, string? bio, string? nicknameColor) => + Task.FromResult(UserOperationResult.Fail(UserError.NotFound, "Not configured")); + + public Task SetAvatarAsync(Guid userId, string asciiArt) => + Task.FromResult(UserOperationResult.Fail(UserError.NotFound, "Not configured")); +}