Add test
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled

This commit is contained in:
Yaojia Wang
2025-11-04 00:20:42 +01:00
parent 26be84de2c
commit 172d0de1fe
13 changed files with 2901 additions and 15 deletions

View File

@@ -302,4 +302,225 @@ public sealed class UserTests
act.Should().Throw<InvalidOperationException>()
.WithMessage("Cannot update SSO profile for local users");
}
[Fact]
public void VerifyEmail_WhenUnverified_ShouldSetVerifiedAt()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.ClearDomainEvents();
// Act
user.VerifyEmail();
// Assert
user.IsEmailVerified.Should().BeTrue();
user.EmailVerifiedAt.Should().NotBeNull();
user.EmailVerificationToken.Should().BeNull();
user.DomainEvents.Should().ContainSingle();
user.DomainEvents.Should().ContainItemsAssignableTo<EmailVerifiedEvent>();
}
[Fact]
public void VerifyEmail_WhenAlreadyVerified_ShouldBeIdempotent()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.VerifyEmail();
var firstVerifiedAt = user.EmailVerifiedAt;
user.ClearDomainEvents();
// Act
user.VerifyEmail();
// Assert
user.EmailVerifiedAt.Should().Be(firstVerifiedAt);
user.DomainEvents.Should().BeEmpty(); // No new event for idempotent operation
}
[Fact]
public void SetEmailVerificationToken_ShouldHashToken()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
const string token = "verification_token";
// Act
user.SetEmailVerificationToken(token);
// Assert
user.EmailVerificationToken.Should().Be(token);
}
[Fact]
public void SetPasswordResetToken_ShouldSetTokenAndExpiration()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
const string token = "reset_token";
var expiresAt = DateTime.UtcNow.AddHours(1);
// Act
user.SetPasswordResetToken(token, expiresAt);
// Assert
user.PasswordResetToken.Should().Be(token);
user.PasswordResetTokenExpiresAt.Should().Be(expiresAt);
}
[Fact]
public void SetPasswordResetToken_ForSsoUser_ShouldThrowException()
{
// Arrange
var user = User.CreateFromSso(
_tenantId,
AuthenticationProvider.Google,
"google-123",
Email.Create("test@example.com"),
FullName.Create("John Doe"));
// Act
var act = () => user.SetPasswordResetToken("token", DateTime.UtcNow.AddHours(1));
// Assert
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Cannot set password reset token for SSO users*");
}
[Fact]
public void ClearPasswordResetToken_ShouldClearTokenAndExpiration()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.SetPasswordResetToken("token", DateTime.UtcNow.AddHours(1));
// Act
user.ClearPasswordResetToken();
// Assert
user.PasswordResetToken.Should().BeNull();
user.PasswordResetTokenExpiresAt.Should().BeNull();
}
[Fact]
public void RecordLoginWithEvent_ShouldUpdateLastLogin()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.ClearDomainEvents();
// Act
user.RecordLoginWithEvent(_tenantId, "192.168.1.1", "Mozilla/5.0");
// Assert
user.LastLoginAt.Should().NotBeNull();
user.LastLoginAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
}
[Fact]
public void RecordLoginWithEvent_ShouldRaiseDomainEvent()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.ClearDomainEvents();
const string ipAddress = "192.168.1.1";
const string userAgent = "Mozilla/5.0";
// Act
user.RecordLoginWithEvent(_tenantId, ipAddress, userAgent);
// Assert
user.DomainEvents.Should().ContainSingle();
user.DomainEvents.Should().ContainItemsAssignableTo<UserLoggedInEvent>();
var domainEvent = user.DomainEvents.First() as UserLoggedInEvent;
domainEvent.Should().NotBeNull();
domainEvent!.UserId.Should().Be(user.Id);
domainEvent.TenantId.Should().Be(_tenantId);
domainEvent.IpAddress.Should().Be(ipAddress);
domainEvent.UserAgent.Should().Be(userAgent);
}
[Fact]
public void Delete_ShouldChangeStatusToDeleted()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
// Act
user.Delete();
// Assert
user.Status.Should().Be(UserStatus.Deleted);
user.UpdatedAt.Should().NotBeNull();
}
[Fact]
public void Suspend_WithDeletedUser_ShouldThrowException()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.Delete();
// Act
var act = () => user.Suspend("Test reason");
// Assert
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Cannot suspend deleted user*");
}
[Fact]
public void Reactivate_WithDeletedUser_ShouldThrowException()
{
// Arrange
var user = User.CreateLocal(
_tenantId,
Email.Create("test@example.com"),
"hash",
FullName.Create("John Doe"));
user.Delete();
// Act
var act = () => user.Reactivate();
// Assert
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Cannot reactivate deleted user*");
}
}