using Omika.Data.Repositories; namespace Omika.Tests.Data; /// /// Tests de la résolution répertoire par répertoire des documents (ancres #id). /// Le chemin est reconstruit depuis la structure Omika : /// [LI_CodeLieu] #[LI_PKID]\[CL_Nom] #[CL_PKID]\[IN_RefInterne] #[IN_PKID]\$DC_Categorie_Id$. /// Objectif : retrouver le répertoire existant même si un libellé a été modifié ou /// contient des espaces en trop, sans jamais créer de doublon — et sans jamais /// lancer de recherche sur le chemin complet. /// public class DocumentAnchoredPathTests : IDisposable { private const string ExpectedPath = @"402 ORCHIDEES 2 #3512\Dupont #12\INT-0001 #3401\Photos #46"; private readonly string _root; public DocumentAnchoredPathTests() { _root = Path.Combine(Path.GetTempPath(), "omika-anchors", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_root); } public void Dispose() { if (Directory.Exists(_root)) { Directory.Delete(_root, recursive: true); } } // --- Extraction de l'ancre ------------------------------------------------ [Fact] public void TryParseAnchor_ExtraitLeDernierIdentifiant() { bool parsed = DocumentPathResolver.TryParseAnchor("Dupont #2 #3512", out string label, out long id); Assert.True(parsed); Assert.Equal(3512, id); Assert.Equal("Dupont #2", label); } [Fact] public void TryParseAnchor_TolereLesEspacesAutourDuDiese() { Assert.True(DocumentPathResolver.TryParseAnchor("Photos # 46", out _, out long id1)); Assert.Equal(46, id1); Assert.True(DocumentPathResolver.TryParseAnchor("Photos #46", out _, out long id2)); Assert.Equal(46, id2); } [Fact] public void TryParseAnchor_SansIdentifiant_RetourneFaux() { Assert.False(DocumentPathResolver.TryParseAnchor("Intervention", out string label, out long id)); Assert.Equal(0, id); Assert.Equal("Intervention", label); } [Fact] public void NormalizeSegmentName_CompacteLesEspacesEtLaCasse() { Assert.Equal( DocumentPathResolver.NormalizeSegmentName("402 ORCHIDEES 2 #3512"), DocumentPathResolver.NormalizeSegmentName("402 ORCHIDEES 2 #3512")); } // --- Recherche du fichier ------------------------------------------------- [Fact] public void RetrouveLeFichier_MalgreUnEspaceDoubleDansLeRepertoireRacine() { // Le disque porte « 402 ORCHIDEES 2 #3512 » (deux espaces), la base produit // « 402 ORCHIDEES 2 #3512 » (un seul). string actualDirectory = CreateDirectoryWithFile(@"402 ORCHIDEES 2 #3512\Dupont #12\INT-0001 #3401\Photos #46"); string? found = DocumentPathResolver.ResolveAnchoredDocumentFile( _root, ExpectedPath, "photo.jpg", Guid.Empty); Assert.NotNull(found); Assert.Equal( Path.GetFullPath(Path.Combine(actualDirectory, "photo.jpg")), Path.GetFullPath(found!)); } [Fact] public void RetrouveLeFichier_MalgreUnLibelleModifie() { // Le client a été renommé : le disque porte « Dupont SA #12 », la base produit // « Dupont #12 ». L'ancre #12 reste identique. string actualDirectory = CreateDirectoryWithFile(@"402 ORCHIDEES 2 #3512\Dupont SA #12\INT-0001 #3401\Photos #46"); string? found = DocumentPathResolver.ResolveAnchoredDocumentFile( _root, ExpectedPath, "photo.jpg", Guid.Empty); Assert.NotNull(found); Assert.Equal( Path.GetFullPath(Path.Combine(actualDirectory, "photo.jpg")), Path.GetFullPath(found!)); } [Fact] public void RetrouveLeFichier_QuandLeSegmentDeCategorieEstAbsent() { // Document historique : pas de sous-répertoire de catégorie sur le disque. string interventionDirectory = CreateDirectoryWithFile(@"402 ORCHIDEES 2 #3512\Dupont #12\INT-0001 #3401"); string? found = DocumentPathResolver.ResolveAnchoredDocumentFile( _root, ExpectedPath, "photo.jpg", Guid.Empty); Assert.NotNull(found); Assert.Equal( Path.GetFullPath(Path.Combine(interventionDirectory, "photo.jpg")), Path.GetFullPath(found!)); } [Fact] public void NeDescendPas_QuandUnNiveauIntermediaireManque() { // Le répertoire du client est absent : la descente doit s'arrêter là et ne // jamais partir en recherche sur le chemin complet. CreateDirectoryWithFile(@"402 ORCHIDEES 2 #3512\INT-0001 #3401\Photos #46"); string? found = DocumentPathResolver.ResolveAnchoredDocumentFile( _root, ExpectedPath, "photo.jpg", Guid.Empty); Assert.Null(found); } [Fact] public void NeConfondPasDeuxIdentifiantsProches() { // #3512 attendu, le disque porte #13512 : aucune correspondance. CreateDirectoryWithFile(@"402 ORCHIDEES 2 #13512\Dupont #12\INT-0001 #3401\Photos #46"); string? found = DocumentPathResolver.ResolveAnchoredDocumentFile( _root, ExpectedPath, "photo.jpg", Guid.Empty); Assert.Null(found); } // --- Création : réutilisation sans doublon -------------------------------- [Fact] public void Creation_ReutiliseLeRepertoireExistant() { string existing = CreateDirectoryWithFile(@"402 ORCHIDEES 2 #3512\Dupont SA #12\INT-0001 #3401\Photos #46"); int directoriesBefore = Directory.GetDirectories(_root, "*", SearchOption.AllDirectories).Length; DocumentPathResolver.AnchorResolution resolution = DocumentPathResolver.EnsureAnchoredDirectory( _root, DocumentPathResolver.ParseAnchors(ExpectedPath)); // Le répertoire réel (deux espaces, libellé « Dupont SA ») est réutilisé tel quel. Assert.NotNull(resolution.RelativeDirectory); Assert.Equal( Path.GetFullPath(existing), Path.GetFullPath(Path.Combine(_root, resolution.RelativeDirectory!))); // Aucun répertoire concurrent n'a été créé. Assert.Equal(directoriesBefore, Directory.GetDirectories(_root, "*", SearchOption.AllDirectories).Length); Assert.False(Directory.Exists(Path.Combine(_root, @"402 ORCHIDEES 2 #3512"))); } [Fact] public void Creation_AjouteUniquementLesSegmentsManquants() { // Client et intervention existent, la catégorie manque. string interventionDirectory = Path.Combine(_root, @"402 ORCHIDEES 2 #3512\Dupont #12\INT-0001 #3401"); Directory.CreateDirectory(interventionDirectory); Directory.CreateDirectory(Path.Combine(_root, @"402 ORCHIDEES 2 #3512\Dupont #12")); DocumentPathResolver.AnchorResolution resolution = DocumentPathResolver.EnsureAnchoredDirectory( _root, DocumentPathResolver.ParseAnchors(ExpectedPath)); Assert.True(resolution.IsComplete); Assert.Equal(4, resolution.ResolvedDepth); string expectedFinal = Path.Combine(interventionDirectory, "Photos #46"); Assert.Equal(Path.GetFullPath(expectedFinal), Path.GetFullPath(resolution.FullDirectory!)); Assert.True(Directory.Exists(expectedFinal)); } [Fact] public void Creation_DepuisUneRacineVide_CreeTouteLArborescence() { DocumentPathResolver.AnchorResolution resolution = DocumentPathResolver.EnsureAnchoredDirectory( _root, DocumentPathResolver.ParseAnchors(ExpectedPath)); Assert.True(resolution.IsComplete); Assert.Equal( Path.GetFullPath(Path.Combine(_root, ExpectedPath)), Path.GetFullPath(resolution.FullDirectory!)); } [Fact] public void ParseAnchors_IgnoreLesSeparateursMultiples() { IReadOnlyList segments = DocumentPathResolver.ParseAnchors(@"\\402 ORCHIDEES 2 #3512\\Dupont #12\"); Assert.Equal(2, segments.Count); Assert.Equal(3512, segments[0].Id); Assert.Equal(12, segments[1].Id); } private string CreateDirectoryWithFile(string relativeDirectory) { string directory = Path.Combine(_root, relativeDirectory); Directory.CreateDirectory(directory); File.WriteAllBytes(Path.Combine(directory, "photo.jpg"), [1, 2, 3]); return directory; } }