Project Init

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-02 23:55:18 +01:00
commit 014d62bcc2
169 changed files with 28867 additions and 0 deletions

View File

@@ -0,0 +1,332 @@
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
using FluentAssertions;
namespace ColaFlow.Domain.Tests.Aggregates;
/// <summary>
/// Unit tests for Epic entity
/// </summary>
public class EpicTests
{
#region Create Tests
[Fact]
public void Create_WithValidData_ShouldCreateEpic()
{
// Arrange
var name = "Epic 1";
var description = "Epic Description";
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
// Act
var epic = Epic.Create(name, description, projectId, createdBy);
// Assert
epic.Should().NotBeNull();
epic.Name.Should().Be(name);
epic.Description.Should().Be(description);
epic.ProjectId.Should().Be(projectId);
epic.Status.Should().Be(WorkItemStatus.ToDo);
epic.Priority.Should().Be(TaskPriority.Medium);
epic.CreatedBy.Should().Be(createdBy);
epic.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
epic.UpdatedAt.Should().BeNull();
epic.Stories.Should().BeEmpty();
}
[Fact]
public void Create_WithNullDescription_ShouldCreateEpicWithEmptyDescription()
{
// Arrange
var name = "Epic 1";
string? description = null;
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
// Act
var epic = Epic.Create(name, description!, projectId, createdBy);
// Assert
epic.Should().NotBeNull();
epic.Description.Should().Be(string.Empty);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void Create_WithEmptyName_ShouldThrowDomainException(string invalidName)
{
// Arrange
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
// Act
Action act = () => Epic.Create(invalidName, "Description", projectId, createdBy);
// Assert
act.Should().Throw<DomainException>()
.WithMessage("Epic name cannot be empty");
}
[Fact]
public void Create_WithNameExceeding200Characters_ShouldThrowDomainException()
{
// Arrange
var name = new string('A', 201);
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
// Act
Action act = () => Epic.Create(name, "Description", projectId, createdBy);
// Assert
act.Should().Throw<DomainException>()
.WithMessage("Epic name cannot exceed 200 characters");
}
[Fact]
public void Create_WithNameExactly200Characters_ShouldSucceed()
{
// Arrange
var name = new string('A', 200);
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
// Act
var epic = Epic.Create(name, "Description", projectId, createdBy);
// Assert
epic.Should().NotBeNull();
epic.Name.Should().Be(name);
}
#endregion
#region CreateStory Tests
[Fact]
public void CreateStory_WithValidData_ShouldCreateStory()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
var storyTitle = "Story 1";
var storyDescription = "Story Description";
var priority = TaskPriority.High;
var createdBy = UserId.Create();
// Act
var story = epic.CreateStory(storyTitle, storyDescription, priority, createdBy);
// Assert
story.Should().NotBeNull();
story.Title.Should().Be(storyTitle);
story.Description.Should().Be(storyDescription);
story.EpicId.Should().Be(epic.Id);
story.Priority.Should().Be(priority);
story.CreatedBy.Should().Be(createdBy);
epic.Stories.Should().ContainSingle();
epic.Stories.Should().Contain(story);
}
[Fact]
public void CreateStory_MultipleStories_ShouldAddToCollection()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
var createdBy = UserId.Create();
// Act
var story1 = epic.CreateStory("Story 1", "Desc 1", TaskPriority.Low, createdBy);
var story2 = epic.CreateStory("Story 2", "Desc 2", TaskPriority.Medium, createdBy);
var story3 = epic.CreateStory("Story 3", "Desc 3", TaskPriority.High, createdBy);
// Assert
epic.Stories.Should().HaveCount(3);
epic.Stories.Should().Contain(new[] { story1, story2, story3 });
}
#endregion
#region UpdateDetails Tests
[Fact]
public void UpdateDetails_WithValidData_ShouldUpdateEpic()
{
// Arrange
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
var originalCreatedAt = epic.CreatedAt;
var newName = "Updated Name";
var newDescription = "Updated Description";
// Act
epic.UpdateDetails(newName, newDescription);
// Assert
epic.Name.Should().Be(newName);
epic.Description.Should().Be(newDescription);
epic.CreatedAt.Should().Be(originalCreatedAt);
epic.UpdatedAt.Should().NotBeNull();
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
[Fact]
public void UpdateDetails_WithNullDescription_ShouldSetEmptyDescription()
{
// Arrange
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
// Act
epic.UpdateDetails("Updated Name", null!);
// Assert
epic.Description.Should().Be(string.Empty);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void UpdateDetails_WithEmptyName_ShouldThrowDomainException(string invalidName)
{
// Arrange
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
// Act
Action act = () => epic.UpdateDetails(invalidName, "Updated Description");
// Assert
act.Should().Throw<DomainException>()
.WithMessage("Epic name cannot be empty");
}
[Fact]
public void UpdateDetails_WithNameExceeding200Characters_ShouldThrowDomainException()
{
// Arrange
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
var name = new string('A', 201);
// Act
Action act = () => epic.UpdateDetails(name, "Updated Description");
// Assert
act.Should().Throw<DomainException>()
.WithMessage("Epic name cannot exceed 200 characters");
}
#endregion
#region UpdateStatus Tests
[Fact]
public void UpdateStatus_WithValidStatus_ShouldUpdateStatus()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
var newStatus = WorkItemStatus.InProgress;
// Act
epic.UpdateStatus(newStatus);
// Assert
epic.Status.Should().Be(newStatus);
epic.UpdatedAt.Should().NotBeNull();
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
[Fact]
public void UpdateStatus_ToAllStatuses_ShouldSucceed()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
// Act & Assert
epic.UpdateStatus(WorkItemStatus.InProgress);
epic.Status.Should().Be(WorkItemStatus.InProgress);
epic.UpdateStatus(WorkItemStatus.InReview);
epic.Status.Should().Be(WorkItemStatus.InReview);
epic.UpdateStatus(WorkItemStatus.Done);
epic.Status.Should().Be(WorkItemStatus.Done);
epic.UpdateStatus(WorkItemStatus.Blocked);
epic.Status.Should().Be(WorkItemStatus.Blocked);
epic.UpdateStatus(WorkItemStatus.ToDo);
epic.Status.Should().Be(WorkItemStatus.ToDo);
}
#endregion
#region UpdatePriority Tests
[Fact]
public void UpdatePriority_WithValidPriority_ShouldUpdatePriority()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
var newPriority = TaskPriority.Urgent;
// Act
epic.UpdatePriority(newPriority);
// Assert
epic.Priority.Should().Be(newPriority);
epic.UpdatedAt.Should().NotBeNull();
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
[Fact]
public void UpdatePriority_ToAllPriorities_ShouldSucceed()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
// Act & Assert
epic.UpdatePriority(TaskPriority.Low);
epic.Priority.Should().Be(TaskPriority.Low);
epic.UpdatePriority(TaskPriority.Medium);
epic.Priority.Should().Be(TaskPriority.Medium);
epic.UpdatePriority(TaskPriority.High);
epic.Priority.Should().Be(TaskPriority.High);
epic.UpdatePriority(TaskPriority.Urgent);
epic.Priority.Should().Be(TaskPriority.Urgent);
}
#endregion
#region Entity Characteristics Tests
[Fact]
public void Stories_Collection_ShouldBeReadOnly()
{
// Arrange
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
// Act & Assert
epic.Stories.Should().BeAssignableTo<IReadOnlyCollection<Story>>();
}
[Fact]
public void Epic_ShouldHaveUniqueId()
{
// Arrange & Act
var projectId = ProjectId.Create();
var createdBy = UserId.Create();
var epic1 = Epic.Create("Epic 1", "Description", projectId, createdBy);
var epic2 = Epic.Create("Epic 2", "Description", projectId, createdBy);
// Assert
epic1.Id.Should().NotBe(epic2.Id);
}
#endregion
}