using System.IdentityModel.Tokens.Jwt; using Application.Services; using Domain.Entities; using Domain.Interface; using Microsoft.Extensions.Configuration; using NSubstitute; namespace Application.UnitTest.Services; public class JwtServiceTests { private readonly IConfiguration _configuration = Substitute.For(); private readonly IUserRepository _userRepository = Substitute.For(); private readonly IUnitOfWork _unitOfWork = Substitute.For(); private readonly JwtService _sut; public JwtServiceTests() { var section = Substitute.For(); section.Value.Returns("veryveryveryveryveryveryverysecretkey"); _configuration.GetSection("Jwt:Key").Returns(section); _configuration["Jwt:Key"].Returns("veryveryveryveryveryveryverysecretkey"); _configuration["Jwt:Issuer"].Returns("https://localhost:7091"); _configuration["Jwt:Audience"].Returns("http://localhost:5184"); _sut = new JwtService(_configuration, _userRepository, _unitOfWork); } [Fact] public async Task GenerateTokenAsync_ShouldReturnToken_WhenUserIsValid() { var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash" }; _userRepository.GetUserRolesByEmailAsync(user.Email) .Returns(["User"]); var token = await _sut.GenerateTokenAsync(user); Assert.NotNull(token); Assert.NotEmpty(token); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(token); Assert.Equal("https://localhost:7091", jwtToken.Issuer); Assert.Contains(jwtToken.Claims, c => c.Type == "email" && c.Value == user.Email); Assert.Contains(jwtToken.Claims, c => c.Type == "UserId" && c.Value == "1"); Assert.Contains(jwtToken.Claims, c => c.Type == "username" && c.Value == user.Username); Assert.Contains(jwtToken.Claims, c => c.Type == "role" && c.Value == "User"); } [Fact] public async Task GenerateTokenAsync_ShouldIncludeAllRoles() { var user = new User { Id = 2, Username = "adminuser", Email = "admin@example.com", Password = "hash" }; _userRepository.GetUserRolesByEmailAsync(user.Email) .Returns(["Admin", "User"]); var token = await _sut.GenerateTokenAsync(user); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(token); var roleClaims = jwtToken.Claims.Where(c => c.Type == "role").Select(c => c.Value).ToList(); Assert.Contains("Admin", roleClaims); Assert.Contains("User", roleClaims); } [Fact] public async Task GenerateAndSaveRefreshTokenAsync_ShouldUpdateUserAndCommit() { var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash" }; var refreshToken = await _sut.GenerateAndSaveRefreshTokenAsync(user); Assert.NotNull(refreshToken); Assert.NotEmpty(refreshToken); Assert.Equal(refreshToken, user.RefreshToken); Assert.NotNull(user.RefreshTokenExpiryTime); Assert.True(user.RefreshTokenExpiryTime > DateTime.UtcNow); _userRepository.Received(1).Update(user); await _unitOfWork.Received(1).CommitAsync(); } [Fact] public async Task ValidateRefreshTokenAsync_ShouldReturnNull_WhenUserNotFound() { _userRepository.GetUserByIdAsync(99).Returns((User?)null); var result = await _sut.ValidateRefreshTokenAsync(99, "some-token"); Assert.Null(result); } [Fact] public async Task ValidateRefreshTokenAsync_ShouldReturnNull_WhenTokenMismatch() { var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash", RefreshToken = "stored-token", RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(1) }; _userRepository.GetUserByIdAsync(1).Returns(user); var result = await _sut.ValidateRefreshTokenAsync(1, "wrong-token"); Assert.Null(result); } [Fact] public async Task ValidateRefreshTokenAsync_ShouldReturnNull_WhenTokenExpired() { var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash", RefreshToken = "expired-token", RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(-1) }; _userRepository.GetUserByIdAsync(1).Returns(user); var result = await _sut.ValidateRefreshTokenAsync(1, "expired-token"); Assert.Null(result); } [Fact] public async Task ValidateRefreshTokenAsync_ShouldReturnUser_WhenTokenValid() { var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash", RefreshToken = "valid-token", RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(1) }; _userRepository.GetUserByIdAsync(1).Returns(user); var result = await _sut.ValidateRefreshTokenAsync(1, "valid-token"); Assert.NotNull(result); Assert.Equal(1, result.Id); } }