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));
}
}
}