using Baya.Application.Common; using Baya.Domain.Entities.Identity; using Baya.Domain.Entities.Verification; using static Baya.Test.Foundation.Verification.VerificationTestSupport; namespace Baya.Test.Foundation.Verification; public class VerificationAggregatorTests { private static readonly DateTimeOffset Now = new(2026, 7, 1, 12, 0, 0, TimeSpan.Zero); private static (NurseVerification Verification, NurseProfile Profile) Build(params VerificationStepStatus[] statuses) { var verification = new NurseVerification { NurseId = 42, Status = VerificationStatus.Pending }; for (var i = 0; i < statuses.Length; i++) verification.Steps.Add(Step(i + 1, StepType(i + 1, $"step_{i}", automated: false), statuses[i])); return (verification, new NurseProfile()); } [Fact] public void Finalize_AllPassed_ApprovesAndFlipsVerified() { var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed); var status = VerificationAggregator.Finalize(verification, profile, Now); Assert.Equal(VerificationStatus.Approved, status); Assert.Equal(VerificationStatus.Approved, verification.Status); Assert.Equal(Now, verification.ApprovedAt); Assert.True(profile.IsVerified); } [Fact] public void Finalize_OneFailed_RejectsAndKeepsUnverified() { var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Failed); VerificationAggregator.Finalize(verification, profile, Now); Assert.Equal(VerificationStatus.Rejected, verification.Status); Assert.Equal(Now, verification.RejectedAt); Assert.Null(verification.ApprovedAt); Assert.False(profile.IsVerified); } [Fact] public void Finalize_OneInReview_SetsInReview() { var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.InReview); VerificationAggregator.Finalize(verification, profile, Now); Assert.Equal(VerificationStatus.InReview, verification.Status); Assert.False(profile.IsVerified); } [Fact] public void Finalize_AllPending_StaysPending() { var (verification, profile) = Build(VerificationStepStatus.Pending, VerificationStepStatus.Pending); VerificationAggregator.Finalize(verification, profile, Now); Assert.Equal(VerificationStatus.Pending, verification.Status); Assert.False(profile.IsVerified); } [Fact] public void Finalize_PreviouslyApproved_ThenExpires_ReversesVerified() { var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed); VerificationAggregator.Finalize(verification, profile, Now); Assert.True(profile.IsVerified); // A required step lapses (the expiry scan) → re-gate. verification.Steps.Last().Status = VerificationStepStatus.Expired; VerificationAggregator.Finalize(verification, profile, Now); Assert.False(profile.IsVerified); Assert.Equal(VerificationStatus.Pending, verification.Status); Assert.Null(verification.ApprovedAt); } [Fact] public void Finalize_Suspended_StaysSuspendedAndUnverified() { var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed); profile.MarkVerified(); verification.Status = VerificationStatus.Suspended; var status = VerificationAggregator.Finalize(verification, profile, Now); Assert.Equal(VerificationStatus.Suspended, status); Assert.False(profile.IsVerified); } [Fact] public void Finalize_NoSteps_DoesNotApprove() { var verification = new NurseVerification { NurseId = 42, Status = VerificationStatus.Pending }; var profile = new NurseProfile(); VerificationAggregator.Finalize(verification, profile, Now); Assert.False(profile.IsVerified); Assert.Equal(VerificationStatus.Pending, verification.Status); } [Fact] public void BlockingStepCodes_ReturnsCodesOfNonPassedSteps() { var (verification, _) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Pending); var blocking = VerificationAggregator.BlockingStepCodes(verification.Steps); Assert.Single(blocking); Assert.Equal("step_1", blocking[0]); } }