using FiscalFlow.Application.Services; using FiscalFlow.Core.Entities; using FiscalFlow.Core.Interfaces; using Microsoft.Extensions.Configuration; using Moq; using Xunit; using FluentAssertions; namespace FiscalFlow.UnitTests.Services; public class AuthServiceTests { private readonly Mock> _userRepositoryMock; private readonly Mock _unitOfWorkMock; private readonly AuthService _authService; public AuthServiceTests() { _userRepositoryMock = new Mock>(); _unitOfWorkMock = new Mock(); var configuration = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["Jwt:SecretKey"] = "this-is-a-test-secret-key-that-is-32-chars-long", ["Jwt:Issuer"] = "TestIssuer", ["Jwt:Audience"] = "TestAudience", ["Jwt:AccessTokenExpirationMinutes"] = "15", ["Jwt:RefreshTokenExpirationDays"] = "7" }) .Build(); _authService = new AuthService( _userRepositoryMock.Object, _unitOfWorkMock.Object, configuration); } [Fact] public async Task RegisterAsync_WithNewEmail_ShouldCreateUser() { var users = new List(); _userRepositoryMock.Setup(x => x.GetAllAsync(It.IsAny())) .ReturnsAsync(users); _userRepositoryMock.Setup(x => x.AddAsync(It.IsAny(), It.IsAny())) .Callback((u, _) => users.Add(u)) .ReturnsAsync((User u, CancellationToken _) => u); _unitOfWorkMock.Setup(x => x.SaveChangesAsync(It.IsAny())) .ReturnsAsync(1); var result = await _authService.RegisterAsync( new Application.Commands.Auth.RegisterCommand( "test@example.com", "Password123!", "Test User")); result.Success.Should().BeTrue(); result.User.Should().NotBeNull(); result.User!.Email.Should().Be("test@example.com"); result.Tokens.Should().NotBeNull(); result.Tokens!.AccessToken.Should().NotBeNullOrEmpty(); result.Tokens.RefreshToken.Should().NotBeNullOrEmpty(); } [Fact] public async Task RegisterAsync_WithExistingEmail_ShouldReturnError() { var existingUser = new User { Email = "test@example.com", HashedPassword = "hashed" }; _userRepositoryMock.Setup(x => x.GetAllAsync(It.IsAny())) .ReturnsAsync(new List { existingUser }); var result = await _authService.RegisterAsync( new Application.Commands.Auth.RegisterCommand( "test@example.com", "Password123!", "Test User")); result.Success.Should().BeFalse(); result.ErrorMessage.Should().Be("Email already registered"); } [Fact] public async Task LoginAsync_WithValidCredentials_ShouldReturnTokens() { var hashedPassword = ComputeHash("Password123!"); var user = new User { Id = Guid.NewGuid(), Email = "test@example.com", HashedPassword = hashedPassword, IsActive = true }; _userRepositoryMock.Setup(x => x.GetAllAsync(It.IsAny())) .ReturnsAsync(new List { user }); _unitOfWorkMock.Setup(x => x.SaveChangesAsync(It.IsAny())) .ReturnsAsync(1); var result = await _authService.LoginAsync( new Application.Commands.Auth.LoginCommand( "test@example.com", "Password123!")); result.Success.Should().BeTrue(); result.User.Should().NotBeNull(); result.Tokens.Should().NotBeNull(); } [Fact] public async Task LoginAsync_WithInvalidPassword_ShouldReturnError() { var user = new User { Email = "test@example.com", HashedPassword = ComputeHash("CorrectPassword"), IsActive = true }; _userRepositoryMock.Setup(x => x.GetAllAsync(It.IsAny())) .ReturnsAsync(new List { user }); var result = await _authService.LoginAsync( new Application.Commands.Auth.LoginCommand( "test@example.com", "WrongPassword")); result.Success.Should().BeFalse(); result.ErrorMessage.Should().Be("Invalid email or password"); } private static string ComputeHash(string password) { using var sha256 = System.Security.Cryptography.SHA256.Create(); var hashedBytes = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)); return Convert.ToBase64String(hashedBytes); } }