using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using FsCheck; using FsCheck.Xunit; using HoneyBox.Core.Services; using HoneyBox.Model.Entities; using HoneyBox.Model.Models.Auth; using Microsoft.Extensions.Logging; using Moq; using Xunit; namespace HoneyBox.Tests.Services; public class JwtServiceTests { private readonly JwtSettings _jwtSettings; private readonly Mock> _mockLogger; private readonly JwtService _jwtService; public JwtServiceTests() { _jwtSettings = new JwtSettings { Secret = "your-secret-key-must-be-at-least-32-characters-long-for-hs256", Issuer = "HoneyBox", Audience = "HoneyBoxUsers", ExpirationMinutes = 1440, RefreshTokenExpirationDays = 7 }; _mockLogger = new Mock>(); _jwtService = new JwtService(_jwtSettings, _mockLogger.Object); } [Fact] public void GenerateToken_WithValidUser_ReturnsValidToken() { // Arrange var user = new User { Id = 1, Nickname = "TestUser", Uid = "uid123", OpenId = "openid123", HeadImg = "https://example.com/avatar.jpg", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; // Act var token = _jwtService.GenerateToken(user); // Assert Assert.NotNull(token); Assert.NotEmpty(token); // Verify token can be read var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(token); Assert.NotNull(jwtToken); Assert.Equal(_jwtSettings.Issuer, jwtToken.Issuer); Assert.Equal(_jwtSettings.Audience, jwtToken.Audiences.First()); } [Fact] public void GenerateToken_WithNullUser_ThrowsArgumentNullException() { // Act & Assert Assert.Throws(() => _jwtService.GenerateToken(null!)); } [Fact] public void ValidateToken_WithValidToken_ReturnsClaimsPrincipal() { // Arrange var user = new User { Id = 1, Nickname = "TestUser", Uid = "uid123", OpenId = "openid123", HeadImg = "https://example.com/avatar.jpg", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; var token = _jwtService.GenerateToken(user); // Act var principal = _jwtService.ValidateToken(token); // Assert Assert.NotNull(principal); var userIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier); Assert.NotNull(userIdClaim); Assert.Equal("1", userIdClaim.Value); } [Fact] public void ValidateToken_WithInvalidToken_ReturnsNull() { // Act var principal = _jwtService.ValidateToken("invalid.token.here"); // Assert Assert.Null(principal); } [Fact] public void ValidateToken_WithNullToken_ReturnsNull() { // Act var principal = _jwtService.ValidateToken(null!); // Assert Assert.Null(principal); } [Fact] public void ValidateToken_WithEmptyToken_ReturnsNull() { // Act var principal = _jwtService.ValidateToken(string.Empty); // Assert Assert.Null(principal); } [Fact] public void GetUserIdFromToken_WithValidToken_ReturnsCorrectUserId() { // Arrange var user = new User { Id = 42, Nickname = "TestUser", Uid = "uid123", OpenId = "openid123", HeadImg = "https://example.com/avatar.jpg", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; var token = _jwtService.GenerateToken(user); // Act var userId = _jwtService.GetUserIdFromToken(token); // Assert Assert.NotNull(userId); Assert.Equal(42, userId); } [Fact] public void GetUserIdFromToken_WithInvalidToken_ReturnsNull() { // Act var userId = _jwtService.GetUserIdFromToken("invalid.token.here"); // Assert Assert.Null(userId); } [Fact] public void GetUserIdFromToken_WithNullToken_ReturnsNull() { // Act var userId = _jwtService.GetUserIdFromToken(null!); // Assert Assert.Null(userId); } [Fact] public void GetUserIdFromToken_WithEmptyToken_ReturnsNull() { // Act var userId = _jwtService.GetUserIdFromToken(string.Empty); // Assert Assert.Null(userId); } /// /// Property 3: 登录成功Token生成 /// For any valid user, generating a token should produce a valid JWT that contains the user's ID /// and can be validated to extract the same user ID. /// Validates: Requirements 3.1, 3.2 /// [Property(MaxTest = 100)] public bool GeneratedTokenContainsCorrectUserId(PositiveInt userId, NonEmptyString nickname) { var user = new User { Id = userId.Item, Nickname = nickname.Item, Uid = $"uid{userId.Item}", OpenId = $"openid{userId.Item}", HeadImg = "https://example.com/avatar.jpg", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; var token = _jwtService.GenerateToken(user); var extractedUserId = _jwtService.GetUserIdFromToken(token); return extractedUserId == userId.Item; } }