using Omika.Core.Compatibility; using Omika.Core.Domain.Entities.Organisation; using Omika.Core.Domain.ValueObjects; using Omika.Data.Mapping.Common; using OmikaModels = Omika.Data.HfSql.Models.Omika; using OmikaMappers = Omika.Data.Mapping.Omika; namespace Omika.Tests.Mapping; /// /// Tests unitaires du mapper Omika → canonique des collaborateurs (table Collaborateur). /// Aucune base réelle, aucun HFSQL : uniquement des objets en mémoire. /// public class OmikaCollaborateurMapperTests { [Fact] public void CollaborateurOmika_Minimal_MapsWithoutExceptionAndKeepsNoFabricatedValue() { var row = new OmikaModels.CollaborateurRow { COPKID = 1 }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Equal(DatabaseSchemaVersion.Omika, result.SourceVersion); Assert.NotNull(result.Value); Assert.Null(result.Value.Nom); Assert.Null(result.Value.Prenom); Assert.Null(result.Value.Civilite); Assert.Null(result.Value.Statut); Assert.Null(result.Value.Coordonnees); Assert.False(result.Value.Actif); Assert.False(result.Value.EstArchive); Assert.NotNull(result.Value.SourceReference); Assert.Equal(1, result.Value.SourceReference!.NumericId); Assert.Equal(DatabaseSchemaVersion.Omika, result.Value.SourceReference!.Source); Assert.Null(result.Value.SourceReference!.EntityGuid); Assert.Empty(result.Warnings); } [Fact] public void CollaborateurOmika_Full_MapsAllCanonicalProperties() { var row = new OmikaModels.CollaborateurRow { COPKID = 42, COCleCivilite = "M", CONom = "Dupont", COPrenom = "Jean", COTrigramme = "JD", COTelFixe = "0472000000", COTelMobile = "0600000000", COEmail = "jean.dupont@ville-lyon.fr", COCleStatut = "ACTIF", COActif = true, GUID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" }; var referenceRows = new Dictionary { ["M"] = new() { PACLE = "M", PALibelle = "M.", PAPKID = 2 }, ["ACTIF"] = new() { PACLE = "ACTIF", PALibelle = "Actif", PAPKID = 3 } }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row, referenceRows); Collaborateur collaborateur = result.Value; Assert.Equal("M.", collaborateur.Civilite!.Label); Assert.Equal("M", collaborateur.Civilite!.Key); Assert.Equal("Actif", collaborateur.Statut!.Label); Assert.Equal("ACTIF", collaborateur.Statut!.Key); Assert.Equal("Dupont", collaborateur.Nom); Assert.Equal("Jean", collaborateur.Prenom); Assert.Equal("JD", collaborateur.Code); Assert.Equal("jean.dupont@ville-lyon.fr", collaborateur.Coordonnees!.Email); Assert.Equal("0472000000", collaborateur.Coordonnees!.Phone); Assert.Equal("0600000000", collaborateur.Coordonnees!.Mobile); Assert.True(collaborateur.Actif); Assert.Equal(42, collaborateur.SourceReference!.NumericId); Assert.Equal(DatabaseSchemaVersion.Omika, collaborateur.SourceReference!.Source); Assert.Equal(Guid.Parse("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"), collaborateur.SourceReference!.EntityGuid); } [Fact] public void CollaborateurOmika_EmptyCoordinates_ProducesNullCoordonnees() { var row = new OmikaModels.CollaborateurRow { COPKID = 5, CONom = "Martin", COEmail = " ", COTelFixe = "", COTelMobile = null }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Null(result.Value.Coordonnees); Assert.Null(result.Value.Prenom); Assert.Equal("Martin", result.Value.Nom); } [Fact] public void CollaborateurOmika_PartialCoordinates_KeepsOnlyProvidedValues() { var row = new OmikaModels.CollaborateurRow { COPKID = 6, COEmail = "m@exemple.fr", COTelFixe = null, COTelMobile = "0600000000" }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.NotNull(result.Value.Coordonnees); Assert.Equal("m@exemple.fr", result.Value.Coordonnees!.Email); Assert.Null(result.Value.Coordonnees!.Phone); Assert.Equal("0600000000", result.Value.Coordonnees!.Mobile); } [Fact] public void CollaborateurOmika_InvalidGuid_ProducesNullEntityGuidAndWarns() { var row = new OmikaModels.CollaborateurRow { COPKID = 7, GUID = "not-a-guid" }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Null(result.Value.SourceReference!.EntityGuid); Assert.Equal("not-a-guid", result.Value.SourceReference!.PhysicalGuid); Assert.Contains(result.Warnings, w => w.Contains(MappingWarningCodes.InvalidPhysicalGuid, StringComparison.Ordinal)); } [Fact] public void CollaborateurOmika_NoGuid_ProducesNullEntityGuid() { var row = new OmikaModels.CollaborateurRow { COPKID = 8 }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Null(result.Value.SourceReference!.EntityGuid); Assert.Null(result.Value.SourceReference!.PhysicalGuid); Assert.Empty(result.Warnings); } [Fact] public void CollaborateurOmika_EmptyOrNullStrings_NeverThrow() { var row = new OmikaModels.CollaborateurRow { CONom = "", COPrenom = " ", COEmail = "", COTelFixe = null, COTelMobile = " ", COTrigramme = "", COCleCivilite = "", COCleStatut = null }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.NotNull(result.Value); Assert.Null(result.Value.Nom); Assert.Null(result.Value.Prenom); Assert.Null(result.Value.Coordonnees); Assert.Null(result.Value.Civilite); Assert.Null(result.Value.Statut); } [Fact] public void CollaborateurOmika_DefaultRow_NeverThrows() { var row = new OmikaModels.CollaborateurRow(); CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.NotNull(result.Value); Assert.Null(result.Value.SourceReference!.NumericId); Assert.False(result.Value.Actif); Assert.False(result.Value.EstArchive); } [Fact] public void CollaborateurOmika_CanonicalDomain_DoesNotExposeHfSqlNames() { var row = new OmikaModels.CollaborateurRow { COPKID = 40, COCleCivilite = "M", CONom = "Dupont", COPrenom = "Jean", COTelFixe = "01", COTelMobile = "06", COEmail = "j@exemple.fr", COActif = true, GUID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" }; var referenceRows = new Dictionary { ["M"] = new() { PACLE = "M", PALibelle = "M.", PAPKID = 2 } }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row, referenceRows); Collaborateur collaborateur = result.Value; string[] forbidden = [ "CO_", "CL_", "PA_", "PKID", "HfSql", "HFSQL", "GUID" ]; AssertHasNoPhysicalNames(collaborateur, forbidden); if (collaborateur.Coordonnees is not null) { AssertHasNoPhysicalNames(collaborateur.Coordonnees, forbidden); } if (collaborateur.SourceReference is not null) { AssertHasNoPhysicalNames(collaborateur.SourceReference, forbidden); } } [Fact] public void CollaborateurOmika_UnresolvedCle_KeepsKeyAndWarns() { var row = new OmikaModels.CollaborateurRow { COPKID = 9, COCleCivilite = "INCONNU", COCleStatut = "AUTRE" }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.NotNull(result.Value.Civilite); Assert.Equal("INCONNU", result.Value.Civilite!.Key); Assert.Equal(string.Empty, result.Value.Civilite!.Label); Assert.NotNull(result.Value.Statut); Assert.Equal("AUTRE", result.Value.Statut!.Key); Assert.Contains(result.Warnings, w => w.Contains("CO_CleCivilite", StringComparison.Ordinal) && w.Contains(MappingWarningCodes.UnresolvedReference, StringComparison.Ordinal)); Assert.Contains(result.Warnings, w => w.Contains("CO_CleStatut", StringComparison.Ordinal) && w.Contains(MappingWarningCodes.UnresolvedReference, StringComparison.Ordinal)); } [Fact] public void CollaborateurOmika_NoCleButLegacyId_FallsBackToLegacyIdAndWarns() { var row = new OmikaModels.CollaborateurRow { COPKID = 10, COIDCivilite = 77, COIDStatut = 88 }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.NotNull(result.Value.Civilite); Assert.Equal(77, result.Value.Civilite!.LegacyId); Assert.NotNull(result.Value.Statut); Assert.Equal(88, result.Value.Statut!.LegacyId); Assert.Contains(result.Warnings, w => w.Contains(MappingWarningCodes.ZombieFieldUsedAsFallback, StringComparison.Ordinal)); } [Fact] public void CollaborateurOmika_NoCleAndZeroLegacyId_ProducesNoReference() { var row = new OmikaModels.CollaborateurRow { COPKID = 11 }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Null(result.Value.Civilite); Assert.Null(result.Value.Statut); } [Fact] public void CollaborateurOmika_FieldsWithoutCanonicalEquivalent_AreReportedAsIgnored() { var row = new OmikaModels.CollaborateurRow { COPKID = 12, COFonction = "Développeur", COPonderation = 1.5f, COIDImport = "IMP-12", COAuPlanning = true, COAccesBO = true, COAccesMobile = true, CreationDate = new DateTime(2024, 1, 1), ModifDate = new DateTime(2024, 6, 1) }; CanonicalMappingResult result = OmikaMappers.OmikaCollaborateurMapper.Map(row); Assert.Equal("Développeur", result.Value.Fonction); Assert.Contains(result.IgnoredFields, f => f == "CO_Ponderation"); Assert.Contains(result.IgnoredFields, f => f == "CO_IDImport"); Assert.Contains(result.IgnoredFields, f => f == "CO_AuPlanning"); Assert.Contains(result.IgnoredFields, f => f == "CO_AccesBO"); Assert.Contains(result.IgnoredFields, f => f == "CO_AccesMobile"); Assert.Contains(result.IgnoredFields, f => f == "CreationDate"); Assert.Contains(result.IgnoredFields, f => f == "ModifDate"); Assert.Null(result.Value.SocieteId); } private static void AssertHasNoPhysicalNames(object value, string[] forbidden) { foreach (var property in value.GetType().GetProperties()) { Assert.DoesNotContain(forbidden, f => property.Name.Contains(f, StringComparison.Ordinal)); } } }