Files
Ho Ngoc Hai 76d75c753b Migrate
2026-05-23 18:37:02 +07:00

395 lines
9.7 KiB
C#

using FluentAssertions;
using StorageService.Domain.AggregatesModel.FileShareAggregate;
using Xunit;
// EN: Alias to avoid collision with System.IO.FileShare
// VI: Alias để tránh xung đột với System.IO.FileShare
using DomainFileShare = StorageService.Domain.AggregatesModel.FileShareAggregate.FileShare;
namespace StorageService.UnitTests.Domain;
/// <summary>
/// EN: Tests for FileShare aggregate root.
/// VI: Kiểm thử cho aggregate root FileShare.
/// </summary>
public class FileShareTests
{
private static readonly Guid ValidFileId = Guid.NewGuid();
private const string ValidSharedBy = "user-123";
private const SharePermission ValidPermission = SharePermission.Download;
#region Constructor Tests
[Fact]
public void Constructor_ValidParams_GeneratesUniqueShareToken()
{
// Arrange & Act
var share1 = CreateValidFileShare();
var share2 = CreateValidFileShare();
// Assert
share1.ShareToken.Should().NotBeNullOrEmpty();
share2.ShareToken.Should().NotBeNullOrEmpty();
share1.ShareToken.Should().NotBe(share2.ShareToken);
}
[Fact]
public void Constructor_ValidParams_SetsCorrectProperties()
{
// Arrange & Act
var expiresAt = DateTime.UtcNow.AddDays(7);
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
SharePermission.Edit,
sharedWith: "user-456",
password: null,
expiresAt: expiresAt,
maxDownloads: 10);
// Assert
share.FileId.Should().Be(ValidFileId);
share.SharedBy.Should().Be(ValidSharedBy);
share.SharedWith.Should().Be("user-456");
share.Permission.Should().Be(SharePermission.Edit);
share.ExpiresAt.Should().Be(expiresAt);
share.MaxDownloads.Should().Be(10);
share.DownloadCount.Should().Be(0);
share.Status.Should().Be(FileShareStatus.Active);
share.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
}
[Fact]
public void Constructor_WithPassword_HashesPassword()
{
// Arrange
var password = "SecureP@ssw0rd!";
// Act
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
password: password);
// Assert
share.PasswordHash.Should().NotBeNullOrEmpty();
share.PasswordHash.Should().NotBe(password); // Ensure hashed
share.PasswordHash!.Length.Should().BeGreaterThan(password.Length); // Hash includes salt
}
[Fact]
public void Constructor_WithoutPassword_PasswordHashIsNull()
{
// Arrange & Act
var share = CreateValidFileShare();
// Assert
share.PasswordHash.Should().BeNull();
}
#endregion
#region IsValid Tests
[Fact]
public void IsValid_ActiveShare_ReturnsTrue()
{
// Arrange
var share = CreateValidFileShare();
// Act
var result = share.IsValid();
// Assert
result.Should().BeTrue();
share.Status.Should().Be(FileShareStatus.Active);
}
[Fact]
public void IsValid_RevokedShare_ReturnsFalse()
{
// Arrange
var share = CreateValidFileShare();
share.Revoke();
// Act
var result = share.IsValid();
// Assert
result.Should().BeFalse();
share.Status.Should().Be(FileShareStatus.Revoked);
}
[Fact]
public void IsValid_ExpiredShare_ReturnsFalseAndUpdatesStatus()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
expiresAt: DateTime.UtcNow.AddMilliseconds(-100)); // Already expired
// Act
var result = share.IsValid();
// Assert
result.Should().BeFalse();
share.Status.Should().Be(FileShareStatus.Expired);
}
[Fact]
public void IsValid_LimitReached_ReturnsFalseAndUpdatesStatus()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
maxDownloads: 2);
// Simulate reaching limit
share.IncrementDownloadCount();
share.IncrementDownloadCount();
// Act
var result = share.IsValid();
// Assert
result.Should().BeFalse();
share.Status.Should().Be(FileShareStatus.LimitReached);
}
[Fact]
public void IsValid_WithFutureExpiration_ReturnsTrue()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
expiresAt: DateTime.UtcNow.AddDays(7));
// Act
var result = share.IsValid();
// Assert
result.Should().BeTrue();
}
[Fact]
public void IsValid_UnderDownloadLimit_ReturnsTrue()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
maxDownloads: 5);
share.IncrementDownloadCount(); // 1/5
// Act
var result = share.IsValid();
// Assert
result.Should().BeTrue();
share.DownloadCount.Should().Be(1);
}
#endregion
#region ValidatePassword Tests
[Fact]
public void ValidatePassword_NoPasswordRequired_ReturnsTrue()
{
// Arrange
var share = CreateValidFileShare(); // No password
// Act
var result = share.ValidatePassword(null);
// Assert
result.Should().BeTrue();
}
[Fact]
public void ValidatePassword_CorrectPassword_ReturnsTrue()
{
// Arrange
var password = "MySecretP@ss123";
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
password: password);
// Act
var result = share.ValidatePassword(password);
// Assert
result.Should().BeTrue();
}
[Fact]
public void ValidatePassword_WrongPassword_ReturnsFalse()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
password: "CorrectPassword");
// Act
var result = share.ValidatePassword("WrongPassword");
// Assert
result.Should().BeFalse();
}
[Fact]
public void ValidatePassword_NullPasswordWhenRequired_ReturnsFalse()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
password: "SomePassword");
// Act
var result = share.ValidatePassword(null);
// Assert
result.Should().BeFalse();
}
[Fact]
public void ValidatePassword_EmptyPasswordWhenRequired_ReturnsFalse()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
password: "SomePassword");
// Act
var result = share.ValidatePassword(string.Empty);
// Assert
result.Should().BeFalse();
}
#endregion
#region IncrementDownloadCount Tests
[Fact]
public void IncrementDownloadCount_UnderLimit_IncreasesCount()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
maxDownloads: 10);
// Act
share.IncrementDownloadCount();
share.IncrementDownloadCount();
share.IncrementDownloadCount();
// Assert
share.DownloadCount.Should().Be(3);
share.Status.Should().Be(FileShareStatus.Active);
}
[Fact]
public void IncrementDownloadCount_ReachesLimit_UpdatesStatus()
{
// Arrange
var share = new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission,
maxDownloads: 2);
// Act
share.IncrementDownloadCount(); // 1
share.IncrementDownloadCount(); // 2 - limit reached
// Assert
share.DownloadCount.Should().Be(2);
share.Status.Should().Be(FileShareStatus.LimitReached);
}
[Fact]
public void IncrementDownloadCount_NoLimit_ContinuesIncrementing()
{
// Arrange
var share = CreateValidFileShare(); // No max downloads
// Act
for (int i = 0; i < 100; i++)
{
share.IncrementDownloadCount();
}
// Assert
share.DownloadCount.Should().Be(100);
share.Status.Should().Be(FileShareStatus.Active);
}
#endregion
#region Revoke Tests
[Fact]
public void Revoke_SetsStatusAndRevokedAt()
{
// Arrange
var share = CreateValidFileShare();
// Act
share.Revoke();
// Assert
share.Status.Should().Be(FileShareStatus.Revoked);
share.RevokedAt.Should().NotBeNull();
share.RevokedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
}
[Fact]
public void Revoke_AlreadyRevoked_UpdatesRevokedAt()
{
// Arrange
var share = CreateValidFileShare();
share.Revoke();
var firstRevokedAt = share.RevokedAt;
// Act
Thread.Sleep(10);
share.Revoke();
// Assert
share.Status.Should().Be(FileShareStatus.Revoked);
// Note: Current implementation updates RevokedAt each time
}
#endregion
#region Helper Methods
private static DomainFileShare CreateValidFileShare()
{
return new DomainFileShare(
ValidFileId,
ValidSharedBy,
ValidPermission);
}
#endregion
}