using FluentAssertions; using RealCV.Application.Models; using RealCV.Infrastructure.Services; namespace RealCV.Tests.Services; public sealed class EducationVerifierServiceTests { private readonly EducationVerifierService _sut = new(); #region Unaccredited Institution Detection [Theory] [InlineData("Belford University")] [InlineData("Ashwood University")] [InlineData("Rochville University")] [InlineData("St Regis University")] public void Verify_UnaccreditedInstitution_ReturnsUnaccredited(string institution) { // Arrange var education = new EducationEntry { Institution = institution, Qualification = "PhD", Subject = "Business", StartDate = new DateOnly(2020, 1, 1), EndDate = new DateOnly(2020, 6, 1) }; // Act var result = _sut.Verify(education); // Assert result.Status.Should().Be("Unaccredited"); result.IsUnaccredited.Should().BeTrue(); result.IsSuspicious.Should().BeTrue(); result.IsVerified.Should().BeFalse(); } [Fact] public void Verify_UnaccreditedInstitution_IncludesVerificationNotes() { // Arrange var education = new EducationEntry { Institution = "Belford University", Qualification = "MBA" }; // Act var result = _sut.Verify(education); // Assert result.VerificationNotes.Should().Contain("QAA/HESA register"); } #endregion #region Suspicious Pattern Detection [Theory] [InlineData("Global Online University")] [InlineData("Premier University of Excellence")] [InlineData("Executive Virtual University")] public void Verify_SuspiciousPatternInstitution_ReturnsSuspicious(string institution) { // Arrange var education = new EducationEntry { Institution = institution }; // Act var result = _sut.Verify(education); // Assert result.Status.Should().Be("Suspicious"); result.IsSuspicious.Should().BeTrue(); result.IsUnaccredited.Should().BeFalse(); result.IsVerified.Should().BeFalse(); } [Theory] [InlineData("University of the Peak District")] [InlineData("University of the Cotswolds")] [InlineData("University of the Lake District")] [InlineData("University of the Dales")] [InlineData("Sheffield Metropolitan University")] // Uses UK pattern but doesn't exist public void Verify_FakeUKInstitution_ReturnsSuspicious(string institution) { // Arrange var education = new EducationEntry { Institution = institution }; // Act var result = _sut.Verify(education); // Assert result.Status.Should().Be("Suspicious"); result.IsSuspicious.Should().BeTrue(); result.IsVerified.Should().BeFalse(); result.VerificationNotes.Should().Contain("UK university naming convention"); } #endregion #region UK Institution Recognition [Theory] [InlineData("University of Cambridge", "University of Cambridge")] [InlineData("Cambridge", "University of Cambridge")] [InlineData("University of Oxford", "University of Oxford")] [InlineData("Oxford", "University of Oxford")] [InlineData("Imperial College London", "Imperial College London")] [InlineData("UCL", "UCL")] // UCL is directly in the recognised list [InlineData("LSE", "LSE")] // LSE is directly in the recognised list public void Verify_RecognisedUKInstitution_ReturnsRecognised(string input, string expectedMatch) { // Arrange var education = new EducationEntry { Institution = input, Qualification = "BSc", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) }; // Act var result = _sut.Verify(education); // Assert result.Status.Should().Be("Recognised"); result.IsVerified.Should().BeTrue(); result.IsUnaccredited.Should().BeFalse(); result.IsSuspicious.Should().BeFalse(); result.MatchedInstitution.Should().Be(expectedMatch); } [Fact] public void Verify_RecognisedInstitution_IncludesVerificationNotes() { // Arrange var education = new EducationEntry { Institution = "University of Manchester" }; // Act var result = _sut.Verify(education); // Assert result.VerificationNotes.Should().Contain("Verified UK higher education institution"); } [Fact] public void Verify_RecognisedInstitutionVariation_NotesMatchedName() { // Arrange var education = new EducationEntry { Institution = "Cambridge" }; // Act var result = _sut.Verify(education); // Assert result.VerificationNotes.Should().Contain("Matched to official name"); result.MatchedInstitution.Should().Be("University of Cambridge"); } #endregion #region Unknown Institutions [Fact] public void Verify_UnknownInstitution_ReturnsUnknown() { // Arrange var education = new EducationEntry { Institution = "University of Ljubljana", Qualification = "BSc" }; // Act var result = _sut.Verify(education); // Assert result.Status.Should().Be("Unknown"); result.IsVerified.Should().BeFalse(); result.IsUnaccredited.Should().BeFalse(); result.IsSuspicious.Should().BeFalse(); result.VerificationNotes.Should().Contain("international institution"); } #endregion #region Date Plausibility [Fact] public void Verify_PlausibleDates_ReturnsPlausible() { // Arrange var education = new EducationEntry { Institution = "University of Bristol", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) }; // Act var result = _sut.Verify(education); // Assert result.DatesArePlausible.Should().BeTrue(); result.DatePlausibilityNotes.Should().BeNull(); } [Fact] public void Verify_TooShortCourseDuration_ReturnsImplausible() { // Arrange var education = new EducationEntry { Institution = "University of Bristol", StartDate = new DateOnly(2020, 1, 1), EndDate = new DateOnly(2020, 6, 1) // 6 months }; // Act var result = _sut.Verify(education); // Assert result.DatesArePlausible.Should().BeFalse(); result.DatePlausibilityNotes.Should().Contain("unusually short"); } [Fact] public void Verify_TooLongCourseDuration_ReturnsImplausible() { // Arrange var education = new EducationEntry { Institution = "University of Bristol", StartDate = new DateOnly(2010, 1, 1), EndDate = new DateOnly(2020, 1, 1) // 10 years }; // Act var result = _sut.Verify(education); // Assert result.DatesArePlausible.Should().BeFalse(); result.DatePlausibilityNotes.Should().Contain("unusually long"); } [Fact] public void Verify_EndDateBeforeStartDate_ReturnsImplausible() { // Arrange var education = new EducationEntry { Institution = "University of Bristol", StartDate = new DateOnly(2021, 1, 1), EndDate = new DateOnly(2020, 1, 1) }; // Act var result = _sut.Verify(education); // Assert result.DatesArePlausible.Should().BeFalse(); result.DatePlausibilityNotes.Should().Contain("before or equal to start date"); } [Fact] public void Verify_NoDates_AssumesPlausible() { // Arrange var education = new EducationEntry { Institution = "University of Bristol" }; // Act var result = _sut.Verify(education); // Assert result.DatesArePlausible.Should().BeTrue(); } #endregion #region VerifyAll [Fact] public void VerifyAll_MultipleEducations_ReturnsResultsForEach() { // Arrange var educations = new List { new() { Institution = "University of Cambridge" }, new() { Institution = "Belford University" }, new() { Institution = "Unknown Foreign University" } }; // Act var results = _sut.VerifyAll(educations); // Assert results.Should().HaveCount(3); results[0].Status.Should().Be("Recognised"); results[1].Status.Should().Be("Unaccredited"); results[2].Status.Should().Be("Unknown"); } [Fact] public void VerifyAll_OverlappingEducation_NotesOverlap() { // Arrange var educations = new List { new() { Institution = "University of Bristol", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) }, new() { Institution = "University of Bath", StartDate = new DateOnly(2020, 9, 1), EndDate = new DateOnly(2023, 6, 1) } }; // Act var results = _sut.VerifyAll(educations); // Assert results[0].DatePlausibilityNotes.Should().Contain("Overlaps with"); results[1].DatePlausibilityNotes.Should().Contain("Overlaps with"); } [Fact] public void VerifyAll_EmploymentBeforeGraduation_ChecksTimeline() { // Arrange var educations = new List { new() { Institution = "University of Bristol", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) } }; var employment = new List { new() { CompanyName = "Tech Corp", JobTitle = "Senior Developer", StartDate = new DateOnly(2018, 1, 1) // Started before education started } }; // Act var results = _sut.VerifyAll(educations, employment); // Assert results[0].DatesArePlausible.Should().BeFalse(); results[0].DatePlausibilityNotes.Should().Contain("months before claimed graduation"); } [Fact] public void VerifyAll_InternshipBeforeGraduation_AllowsTimeline() { // Arrange var educations = new List { new() { Institution = "University of Bristol", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) } }; var employment = new List { new() { CompanyName = "Tech Corp", JobTitle = "Software Intern", StartDate = new DateOnly(2019, 6, 1) } }; // Act var results = _sut.VerifyAll(educations, employment); // Assert // Should be plausible because it's an internship results[0].DatesArePlausible.Should().BeTrue(); } #endregion #region Data Preservation [Fact] public void Verify_PreservesAllClaimedData() { // Arrange var education = new EducationEntry { Institution = "University of Bristol", Qualification = "BSc Computer Science", Subject = "Computer Science", Grade = "First Class Honours", StartDate = new DateOnly(2018, 9, 1), EndDate = new DateOnly(2021, 6, 1) }; // Act var result = _sut.Verify(education); // Assert result.ClaimedInstitution.Should().Be("University of Bristol"); result.ClaimedQualification.Should().Be("BSc Computer Science"); result.ClaimedSubject.Should().Be("Computer Science"); result.ClaimedStartDate.Should().Be(new DateOnly(2018, 9, 1)); result.ClaimedEndDate.Should().Be(new DateOnly(2021, 6, 1)); } #endregion }