namespace Domain.Tests.Services; using Domain.Entities; using Domain.Exceptions; using Domain.Services; using Domain.ValueObjects; using FluentAssertions; using Xunit; public class EnrollmentDomainServiceTests { private readonly EnrollmentDomainService _sut = new(); private static Email ValidEmail => Email.Create("test@example.com"); [Fact] public void ValidateEnrollment_WhenValid_ShouldNotThrow() { var student = new Student("John Doe", ValidEmail); var subject = new Subject("Math", professorId: 1); var act = () => _sut.ValidateEnrollment(student, subject); act.Should().NotThrow(); } [Fact] public void ValidateEnrollment_WhenMaxEnrollmentsReached_ShouldThrow() { var student = new Student("John Doe", ValidEmail); AddEnrollmentsWithDifferentProfessors(student, 3); var subject = new Subject("Physics", professorId: 99); var act = () => _sut.ValidateEnrollment(student, subject); act.Should().Throw() .Which.Code.Should().Be("MAX_ENROLLMENTS"); } [Fact] public void ValidateEnrollment_WhenSameProfessor_ShouldThrow() { var student = new Student("John Doe", ValidEmail); var existingSubject = new Subject("Math", professorId: 1); AddEnrollmentWithSubject(student, existingSubject); var newSubject = new Subject("Algebra", professorId: 1); var act = () => _sut.ValidateEnrollment(student, newSubject); act.Should().Throw() .Which.Code.Should().Be("SAME_PROFESSOR"); } [Fact] public void ValidateEnrollment_WhenDuplicateSubject_ShouldThrow() { var student = new Student("John Doe", ValidEmail); var subject = new Subject("Math", professorId: 1); SetSubjectId(subject, 10); AddEnrollmentWithSubject(student, subject); // Same subject ID but different professor to bypass professor check var duplicateSubject = new Subject("Math", professorId: 2); SetSubjectId(duplicateSubject, 10); var act = () => _sut.ValidateEnrollment(student, duplicateSubject); act.Should().Throw() .Which.Code.Should().Be("DUPLICATE_ENROLLMENT"); } [Fact] public void CreateEnrollment_WhenValid_ShouldCreateAndAddToStudent() { var student = new Student("John Doe", ValidEmail); var subject = new Subject("Math", professorId: 1); var enrollment = _sut.CreateEnrollment(student, subject); enrollment.Should().NotBeNull(); student.Enrollments.Should().Contain(enrollment); enrollment.StudentId.Should().Be(student.Id); enrollment.SubjectId.Should().Be(subject.Id); } [Fact] public void CreateEnrollment_WhenInvalid_ShouldNotAddToStudent() { var student = new Student("John Doe", ValidEmail); AddEnrollmentsWithDifferentProfessors(student, 3); var subject = new Subject("Physics", professorId: 99); var act = () => _sut.CreateEnrollment(student, subject); act.Should().Throw(); student.Enrollments.Should().HaveCount(3); } private static void AddEnrollmentsWithDifferentProfessors(Student student, int count) { for (int i = 0; i < count; i++) { var subject = new Subject($"Subject{i}", professorId: i + 1); SetSubjectId(subject, i + 1); AddEnrollmentWithSubject(student, subject); } } private static void AddEnrollmentWithSubject(Student student, Subject subject) { var enrollment = new Enrollment(student.Id, subject.Id); SetSubjectOnEnrollment(enrollment, subject); student.AddEnrollment(enrollment); } private static void SetSubjectOnEnrollment(Enrollment enrollment, Subject subject) { typeof(Enrollment).GetProperty("Subject")!.SetValue(enrollment, subject); } private static void SetSubjectId(Subject subject, int id) { typeof(Subject).GetProperty("Id")!.SetValue(subject, id); } }