using Omika.Core.Compatibility; using Omika.Core.Domain.Entities.Organisation; using Omika.Core.Domain.ValueObjects; using Omika.Data.Mapping.Common; using BatikModels = Omika.Data.HfSql.Models.Batik; using BatikMappers = Omika.Data.Mapping.Batik; namespace Omika.Tests.Mapping; /// /// Tests unitaires du mapper Batik → canonique des collaborateurs (table Collaborateur). /// Aucune base réelle, aucun HFSQL : uniquement des objets en mémoire. /// public class BatikCollaborateurMapperTests { // ---- 1. Collaborateur Batik minimal ------------------------------------------- [Fact] public void CollaborateurBatik_Minimal_MapsWithoutExceptionAndKeepsNoFabricatedValue() { var row = new BatikModels.CollaborateurRow { COPKID = 1 }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.Equal(DatabaseSchemaVersion.Batik, 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.Batik, result.Value.SourceReference!.Source); Assert.Null(result.Value.SourceReference!.EntityGuid); Assert.Empty(result.Warnings); } // ---- 2. Collaborateur Batik complet ------------------------------------------- [Fact] public void CollaborateurBatik_Full_MapsAllCanonicalProperties() { var row = new BatikModels.CollaborateurRow { COPKID = 42, COIDCivilite = 2, CONom = "Dupont", COPrenom = "Jean", COTrigramme = "JD", COTelFixe = "0472000000", COTelMobile = "0600000000", COEmail = "jean.dupont@ville-lyon.fr", COIDStatut = 3, COActif = true, COIDImport = "IMP-B-42" }; var referenceRows = new Dictionary { [2] = new() { PAPKID = 2, PACode = "C", PAValeur = "1", PALibelle = "M." }, [3] = new() { PAPKID = 3, PACode = "S", PAValeur = "1", PALibelle = "Actif" } }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row, referenceRows); Collaborateur collaborateur = result.Value; Assert.Equal("M.", collaborateur.Civilite!.Label); Assert.Equal(2, collaborateur.Civilite!.LegacyId); Assert.Equal("Actif", collaborateur.Statut!.Label); Assert.Equal(3, collaborateur.Statut!.LegacyId); 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.Batik, collaborateur.SourceReference!.Source); } // ---- 3. Coordonnées nulles ---------------------------------------------------- [Fact] public void CollaborateurBatik_EmptyCoordinates_ProducesNullCoordonnees() { var row = new BatikModels.CollaborateurRow { COPKID = 5, CONom = "Martin", COEmail = " ", COTelFixe = "", COTelMobile = null }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.Null(result.Value.Coordonnees); Assert.Null(result.Value.Prenom); Assert.Equal("Martin", result.Value.Nom); } [Fact] public void CollaborateurBatik_PartialCoordinates_KeepsOnlyProvidedValues() { var row = new BatikModels.CollaborateurRow { COPKID = 6, COEmail = "m@exemple.fr", COTelFixe = null, COTelMobile = "0600000000" }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.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); } // ---- 4. Conservation de l'identifiant source ---------------------------------- [Fact] public void CollaborateurBatik_SourceIdentifier_IsPreservedWithoutFabricatedGuid() { var row = new BatikModels.CollaborateurRow { COPKID = 1234, COIDImport = "IMP-B" }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.NotNull(result.Value.SourceReference); Assert.Equal(DatabaseSchemaVersion.Batik, result.Value.SourceReference!.Source); Assert.Equal(1234, result.Value.SourceReference!.NumericId); Assert.Equal("1234", result.Value.SourceReference!.PublicIdentifier); Assert.Null(result.Value.SourceReference!.EntityGuid); Assert.Null(result.Value.SourceReference!.PhysicalGuid); } // ---- 5. Aucune exception sur les chaînes vides ---------------------------------- [Fact] public void CollaborateurBatik_EmptyOrNullStrings_NeverThrow() { var row = new BatikModels.CollaborateurRow { CONom = "", COPrenom = " ", COEmail = "", COTelFixe = null, COTelMobile = " ", COTrigramme = "", COIDImport = "" }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.NotNull(result.Value); Assert.Null(result.Value.Nom); Assert.Null(result.Value.Prenom); Assert.Null(result.Value.Coordonnees); Assert.Empty(result.Warnings); } [Fact] public void CollaborateurBatik_DefaultRow_NeverThrows() { var row = new BatikModels.CollaborateurRow(); CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.NotNull(result.Value); Assert.Null(result.Value.SourceReference!.NumericId); Assert.False(result.Value.Actif); Assert.False(result.Value.EstArchive); } // ---- 6. Absence de noms physiques HFSQL dans le domaine canonique -------------- [Fact] public void CollaborateurBatik_CanonicalDomain_DoesNotExposeHfSqlNames() { var row = new BatikModels.CollaborateurRow { COPKID = 40, COIDCivilite = 2, CONom = "Dupont", COPrenom = "Jean", COTelFixe = "01", COTelMobile = "06", COEmail = "j@exemple.fr", COActif = true, COIDImport = "IMP-40" }; var referenceRows = new Dictionary { [2] = new() { PAPKID = 2, PACode = "C", PAValeur = "1", PALibelle = "M." } }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.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); } } // ---- Référentiels non résolus -------------------------------------------------- [Fact] public void CollaborateurBatik_UnresolvedCiviliteAndStatut_KeepsLegacyIdAndWarns() { var row = new BatikModels.CollaborateurRow { COPKID = 7, COIDCivilite = 77, COIDStatut = 88 }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.NotNull(result.Value.Civilite); Assert.Equal(77, result.Value.Civilite!.LegacyId); Assert.Equal(string.Empty, result.Value.Civilite!.Label); Assert.NotNull(result.Value.Statut); Assert.Equal(88, result.Value.Statut!.LegacyId); Assert.Contains(result.Warnings, w => w.Contains("CO_IDCivilite", StringComparison.Ordinal) && w.Contains(MappingWarningCodes.UnresolvedReference, StringComparison.Ordinal)); Assert.Contains(result.Warnings, w => w.Contains("CO_IDStatut", StringComparison.Ordinal) && w.Contains(MappingWarningCodes.UnresolvedReference, StringComparison.Ordinal)); } [Fact] public void CollaborateurBatik_ZeroCiviliteAndStatut_ProducesNoReference() { var row = new BatikModels.CollaborateurRow { COPKID = 8, COIDCivilite = 0, COIDStatut = 0 }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.Map(row); Assert.Null(result.Value.Civilite); Assert.Null(result.Value.Statut); Assert.Empty(result.Warnings); } // ---- Rubriques sans équivalent -------------------------------------------------- [Fact] public void CollaborateurBatik_FieldsWithoutCanonicalEquivalent_AreReportedAsIgnored() { var row = new BatikModels.CollaborateurRow { COPKID = 9, COFonction = "Développeur", COPonderation = 1.5f, COIDImport = "IMP-9", COAuPlanning = true, COAccesBO = true, COAccesMobile = true, CreationDate = new DateTime(2024, 1, 1), ModifDate = new DateTime(2024, 6, 1) }; CanonicalMappingResult result = BatikMappers.BatikCollaborateurMapper.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); } // ---- Helper --------------------------------------------------------------------- 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)); } } }