diff --git a/FruitBankHybrid.Shared.Tests/TestData/ToonTestData.cs b/FruitBankHybrid.Shared.Tests/TestData/ToonTestData.cs new file mode 100644 index 00000000..5b9f1993 --- /dev/null +++ b/FruitBankHybrid.Shared.Tests/TestData/ToonTestData.cs @@ -0,0 +1,33 @@ +namespace FruitBankHybrid.Shared.Tests.TestData; + +// Demo entity-k a teszteléshez +public class TestOrder +{ + public int Id { get; set; } + public int CustomerId { get; set; } + public TestCustomer? Customer { get; set; } + public List OrderItems { get; set; } = new(); +} + +public class TestCustomer +{ + public int Id { get; set; } + public string Name { get; set; } = ""; + public List Orders { get; set; } = new(); +} + +public class TestOrderItem +{ + public int Id { get; set; } + public int OrderId { get; set; } + public TestOrder? Order { get; set; } + public int ProductId { get; set; } + public TestProduct? Product { get; set; } +} + +public class TestProduct +{ + public int Id { get; set; } + public string Name { get; set; } = ""; + public List OrderItems { get; set; } = new(); +} \ No newline at end of file diff --git a/FruitBankHybrid.Shared.Tests/ToonTests.cs b/FruitBankHybrid.Shared.Tests/ToonTests.cs index 17e364e3..3cdbca25 100644 --- a/FruitBankHybrid.Shared.Tests/ToonTests.cs +++ b/FruitBankHybrid.Shared.Tests/ToonTests.cs @@ -39,6 +39,7 @@ public sealed class ToonTests [TestMethod] public void OrderDtoToToon() { + var toon = AcToonSerializer.SerializeTypeMetadata(); Console.WriteLine(toon); @@ -101,4 +102,208 @@ public sealed class ToonTests } } } + + [TestMethod] + public void ToonTypes_NavigationMetadata_ShouldBeComplete() + { + var toon = AcToonSerializer.SerializeTypeMetadata(); + Console.WriteLine(toon); + Console.WriteLine("\n=== NAVIGATION METADATA ELLENŐRZÉS ===\n"); + + var lines = toon.Split('\n').Select(x => x.TrimEnd()).ToList(); + + // Ismerten egyirányú kapcsolatok - ezeknél nincs inverse property a másik oldalon + // Customer: NopCommerce domain entity, nincs benne Orders kollekció + // OrderNotes: OrderNote osztályban nincs Order navigation property + // ProductDto: nincs benne OrderItems kollekció + // GenericAttributes: polimorf kapcsolat ExpressionPredicate-tel, nincs inverse ÉS nincs egyértelmű FK + // FONTOS: Csak az inverse-property hiányát engedjük! Az other-key-nek léteznie kell! + var knownUnidirectionalNavigations = new HashSet + { + "Customer", + "OrderNotes", + "ProductDto", + "GenericAttributes", + "ShippingDocumentFile", + "Pallet" + }; + + // GenericAttributes speciális eset - polimorf, nincs other-key sem + var knownPolymorphicNavigations = new HashSet + { + "GenericAttributes" + }; + + // FK property-k NEM tartalmazhatnak foreign-key attribútumot + for (int i = 0; i < lines.Count; i++) + { + var line = lines[i].Trim(); + if (line.EndsWith("Id: int") || line.EndsWith("Id: int?")) + { + int j = i + 1; + while (j < lines.Count) + { + if (lines[j].StartsWith(" ") && !lines[j].StartsWith(" ")) + break; + + if (lines[j].StartsWith(" ")) + { + var metaLine = lines[j].Trim(); + if (metaLine.StartsWith("foreign-key:")) + { + Assert.Fail($"FK property nem tartalmazhat foreign-key attribútumot: {line} -> {metaLine}"); + } + } + j++; + } + } + } + + Console.WriteLine("✓ FK property-k nem tartalmaznak foreign-key attribútumot\n"); + + // Számoljuk meg a hiányzó navigation metadatokat + var missingMetadata = new List(); + var skippedUnidirectional = new List(); + + for (int i = 0; i < lines.Count; i++) + { + var line = lines[i].Trim(); + + // Navigation property-k keresése + if (line.Contains(": ") && + !line.Contains(": int") && !line.Contains(": string") && + !line.Contains(": DateTime") && !line.Contains(": decimal") && + !line.Contains(": bool") && !line.Contains(": Guid") && + !line.Contains(": double") && !line.Contains(": float") && + !line.Contains("description:") && !line.Contains("purpose:") && + !line.Contains("navigation:") && !line.Contains("foreign-key:") && + !line.Contains("table-name:") && !line.Contains("constraints:") && + !line.Contains("inverse-property:") && !line.Contains("other-key:") && + !line.Contains("primary-key:") && !line.Contains("examples:") && + !line.Contains("@meta") && !line.Contains("@types") && + !line.Contains("version") && !line.Contains("format") && !line.Contains("source-code-language") && + !line.Contains("underlying-type:") && !line.Contains("default-value:") && !line.Contains("values:")) + { + var propName = line.Split(':')[0].Trim(); + if (string.IsNullOrEmpty(propName) || propName == "types") continue; + + // Következő sorok metadatainak összegyűjtése + var metadata = new HashSet(); + int j = i + 1; + while (j < lines.Count && lines[j].StartsWith(" ") && lines[j].Trim().Contains(':')) + { + var metaLine = lines[j].Trim(); + if (metaLine.StartsWith("navigation:")) metadata.Add("navigation"); + if (metaLine.StartsWith("foreign-key:")) metadata.Add("foreign-key"); + if (metaLine.StartsWith("inverse-property:")) metadata.Add("inverse-property"); + if (metaLine.StartsWith("other-key:")) metadata.Add("other-key"); + j++; + } + + // Ha van navigation attribútum, ellenőrizzük a szükséges metadatokat + if (metadata.Contains("navigation")) + { + var navLine = lines.Skip(i + 1).FirstOrDefault(x => x.Trim().StartsWith("navigation:")); + if (navLine != null) + { + var isUnidirectional = knownUnidirectionalNavigations.Contains(propName); + var isPolymorphic = knownPolymorphicNavigations.Contains(propName); + + if (navLine.Contains("many-to-one")) + { + if (!metadata.Contains("foreign-key")) + missingMetadata.Add($"{propName} (ManyToOne): hiányzik foreign-key"); + + if (!metadata.Contains("inverse-property")) + { + if (isUnidirectional) + skippedUnidirectional.Add($"{propName} (ManyToOne): egyirányú kapcsolat, nincs inverse"); + else + missingMetadata.Add($"{propName} (ManyToOne): hiányzik inverse-property"); + } + } + else if (navLine.Contains("one-to-many")) + { + // other-key: polimorf kapcsolatoknál nem kötelező + if (!metadata.Contains("other-key")) + { + if (isPolymorphic) + { + skippedUnidirectional.Add($"{propName} (OneToMany): polimorf kapcsolat, nincs other-key"); + } + else + { + // DEBUG: részletes info + Console.WriteLine($"\n[DEBUG] {propName} (OneToMany) - other-key hiányzik!"); + + // Keressük meg a property típusát a Toon outputban + var propTypePart = line.Split(':').LastOrDefault()?.Trim() ?? ""; + Console.WriteLine($" Property type: {propTypePart}"); + + // Ha List formátum, keressük meg X-et + if (propTypePart.StartsWith("List<") && propTypePart.EndsWith(">")) + { + var elementTypeName = propTypePart.Substring(5, propTypePart.Length - 6); + Console.WriteLine($" Element type: {elementTypeName}"); + + // Keressük meg az element type definícióját + var elementTypeDefIndex = lines.FindIndex(l => l.Trim().StartsWith($"{elementTypeName}:")); + if (elementTypeDefIndex >= 0) + { + Console.WriteLine($" Element type definition found at line {elementTypeDefIndex}"); + // Listázzuk ki az element type property-jeit amik "Id"-re végződnek + for (int k = elementTypeDefIndex + 1; k < lines.Count; k++) + { + var propLine = lines[k]; + if (!propLine.StartsWith(" ")) break; // Új típus definíció + if (propLine.StartsWith(" ")) continue; // Metaadat, skip + + var trimmed = propLine.Trim(); + if (trimmed.EndsWith(": int") && trimmed.Contains("Id")) + { + Console.WriteLine($" FK candidate: {trimmed}"); + } + } + } + } + + missingMetadata.Add($"{propName} (OneToMany): hiányzik other-key"); + } + } + + if (!metadata.Contains("inverse-property")) + { + if (isUnidirectional) + skippedUnidirectional.Add($"{propName} (OneToMany): egyirányú kapcsolat, nincs inverse"); + else + missingMetadata.Add($"{propName} (OneToMany): hiányzik inverse-property"); + } + } + } + } + } + } + + if (skippedUnidirectional.Count > 0) + { + Console.WriteLine("EGYIRÁNYÚ/POLIMORF KAPCSOLATOK (nem hiba):"); + foreach (var skipped in skippedUnidirectional) + { + Console.WriteLine($" ℹ {skipped}"); + } + Console.WriteLine(); + } + + if (missingMetadata.Count > 0) + { + Console.WriteLine("HIÁNYZÓ METAADATOK:"); + foreach (var missing in missingMetadata) + { + Console.WriteLine($" - {missing}"); + } + Assert.Fail($"Hiányzó navigation metaadatok: {missingMetadata.Count} db"); + } + + Console.WriteLine("✓ Minden navigation property tartalmazza a szükséges metadatokat"); + } } \ No newline at end of file