SemanticTreeTestRunner.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using QuestPDF.Drawing;
  2. using QuestPDF.Infrastructure;
  3. namespace QuestPDF.ConformanceTests.TestEngine;
  4. internal static class SemanticTreeTestRunner
  5. {
  6. public static void TestSemanticTree(this IDocument document, SemanticTreeNode? semanticTreeRootNode)
  7. {
  8. Settings.EnableCaching = false;
  9. Settings.EnableDebugging = false;
  10. var canvas = new SemanticAwareDocumentCanvas();
  11. var settings = new DocumentSettings { PDFA_Conformance = PDFA_Conformance.PDFA_3A };
  12. DocumentGenerator.RenderDocument(canvas, document, settings);
  13. CompareSemanticTrees(canvas.SemanticTree, semanticTreeRootNode);
  14. }
  15. private static void CompareSemanticTrees(SemanticTreeNode? actualRoot, SemanticTreeNode? expectedRoot)
  16. {
  17. if (expectedRoot == null && actualRoot == null)
  18. return;
  19. if (expectedRoot == null)
  20. {
  21. Assert.Fail($"Expected null but got node of type '{actualRoot?.Type}'");
  22. return;
  23. }
  24. if (actualRoot == null)
  25. {
  26. Assert.Fail($"Expected node of type '{expectedRoot.Type}' but got null");
  27. return;
  28. }
  29. var currentPath = new Stack<string>();
  30. try
  31. {
  32. Compare(actualRoot, expectedRoot);
  33. }
  34. catch
  35. {
  36. var pathText = string.Join(" -> ", currentPath.Reverse());
  37. Console.WriteLine("Problem location");
  38. Console.WriteLine(pathText);
  39. throw;
  40. }
  41. void Compare(SemanticTreeNode actual, SemanticTreeNode expected)
  42. {
  43. if (!currentPath.Any())
  44. currentPath.Push(actual.Type);
  45. if (expected.NodeId != 0)
  46. Assert.That(actual.NodeId, Is.EqualTo(expected.NodeId), "NodeId mismatch");
  47. Assert.That(actual.Type, Is.EqualTo(expected.Type), "Type mismatch");
  48. Assert.That(actual.Alt, Is.EqualTo(expected.Alt), "Alt mismatch");
  49. Assert.That(actual.Lang, Is.EqualTo(expected.Lang), "Lang mismatch");
  50. CompareAttributes();
  51. CompareChildren();
  52. void CompareChildren()
  53. {
  54. Assert.That(actual.Children.Count, Is.EqualTo(expected.Children.Count), "Children count mismatch");
  55. var hasMultipleChildren = actual.Children.Count > 1;
  56. foreach (var (actualChild, expectedChild) in actual.Children.Zip(expected.Children))
  57. {
  58. var prefix = hasMultipleChildren ? $"{actual.Children.IndexOf(actualChild)}:" : "";
  59. currentPath.Push(prefix + actualChild.Type);
  60. Compare(actualChild, expectedChild);
  61. currentPath.Pop();
  62. }
  63. }
  64. void CompareAttributes()
  65. {
  66. Assert.That(actual.Attributes.Count, Is.EqualTo(expected.Attributes.Count), "Attribute count mismatch");
  67. var actualList = actual.Attributes.OrderBy(a => a.Owner).ThenBy(a => a.Name);
  68. var expectedList = expected.Attributes.OrderBy(a => a.Owner).ThenBy(a => a.Name);
  69. foreach (var (actualAttribute, expectedAttribute) in actualList.Zip(expectedList))
  70. {
  71. Assert.That(actualAttribute.Owner, Is.EqualTo(expectedAttribute.Owner), "Attribute owner mismatch");
  72. Assert.That(actualAttribute.Name, Is.EqualTo(expectedAttribute.Name), "Attribute name mismatch");
  73. Assert.That(actualAttribute.Value, Is.EqualTo(expectedAttribute.Value), $"Attribute value mismatch for '{expectedAttribute.Owner}:{expectedAttribute.Name}");
  74. }
  75. }
  76. }
  77. }
  78. }
  79. internal static class ExpectedSemanticTree
  80. {
  81. public static SemanticTreeNode DocumentRoot(Action<SemanticTreeNode> configuration)
  82. {
  83. var root = new SemanticTreeNode
  84. {
  85. Type = "Document"
  86. };
  87. configuration(root);
  88. return root;
  89. }
  90. public static void Child(this SemanticTreeNode parent, string type, Action<SemanticTreeNode>? configuration = null)
  91. {
  92. var child = new SemanticTreeNode
  93. {
  94. Type = type
  95. };
  96. configuration?.Invoke(child);
  97. parent.Children.Add(child);
  98. }
  99. public static SemanticTreeNode Id(this SemanticTreeNode node, int id)
  100. {
  101. node.NodeId = id;
  102. return node;
  103. }
  104. public static SemanticTreeNode Attribute(this SemanticTreeNode node, string owner, string name, object value)
  105. {
  106. var attribute = new SemanticTreeNode.Attribute
  107. {
  108. Owner = owner,
  109. Name = name,
  110. Value = value
  111. };
  112. node.Attributes.Add(attribute);
  113. return node;
  114. }
  115. public static SemanticTreeNode Alt(this SemanticTreeNode node, string alt)
  116. {
  117. node.Alt = alt;
  118. return node;
  119. }
  120. public static SemanticTreeNode Lang(this SemanticTreeNode node, string lang)
  121. {
  122. node.Lang = lang;
  123. return node;
  124. }
  125. }