LayoutTestValidator.cs 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using QuestPDF.Infrastructure;
  2. namespace QuestPDF.LayoutTests.TestEngine;
  3. internal static class LayoutTestValidator
  4. {
  5. public static void Validate(LayoutTestResult result)
  6. {
  7. if (result.ActualLayout.GeneratesInfiniteLayout && !result.ExpectedLayout.GeneratesInfiniteLayout)
  8. throw new LayoutTestException("Provided content generates unexpected infinite layout");
  9. if (!result.ActualLayout.GeneratesInfiniteLayout && result.ExpectedLayout.GeneratesInfiniteLayout)
  10. throw new LayoutTestException("Provided content is expected to generate infinite layout but it does not");
  11. var actualPages = result.ActualLayout.Pages;
  12. var expectedPages = result.ExpectedLayout.Pages;
  13. if (actualPages.Count != expectedPages.Count)
  14. throw new LayoutTestException($"Content return layout with {actualPages.Count} pages but expected {expectedPages.Count} pages");
  15. foreach (var i in Enumerable.Range(0, actualPages.Count))
  16. {
  17. try
  18. {
  19. var actualPage = actualPages.ElementAt(i);
  20. var expectedPage = expectedPages.ElementAt(i);
  21. ValidatePage(actualPage, expectedPage);
  22. }
  23. catch (LayoutTestException exception)
  24. {
  25. throw new LayoutTestException($"Found issue on page number {i + 1}: {exception.Message}");
  26. }
  27. catch (Exception exception)
  28. {
  29. throw new LayoutTestException($"Encountered exception during validating page number {i + 1}", exception);
  30. }
  31. }
  32. static void ValidatePage(LayoutTestResult.PageLayout actualLayout, LayoutTestResult.PageLayout expectedLayout)
  33. {
  34. if (Math.Abs(actualLayout.RequiredArea.Width - expectedLayout.RequiredArea.Width) > Size.Epsilon)
  35. throw new LayoutTestException($"Required horizontal area is equal to {actualLayout.RequiredArea.Width} but expected {expectedLayout.RequiredArea.Width}");
  36. if (Math.Abs(actualLayout.RequiredArea.Height - expectedLayout.RequiredArea.Height) > Size.Epsilon)
  37. throw new LayoutTestException($"Required vertical area is equal to {actualLayout.RequiredArea.Height} but expected {expectedLayout.RequiredArea.Height}");
  38. if (actualLayout.Mocks.Count != expectedLayout.Mocks.Count)
  39. throw new LayoutTestException($"Visible {actualLayout.Mocks.Count} mocks but expected {expectedLayout.Mocks.Count}");
  40. ValidatePositionAndSizeOfMocks(actualLayout, expectedLayout);
  41. ValidateDrawingOrder(actualLayout, expectedLayout);
  42. }
  43. static void ValidatePositionAndSizeOfMocks(LayoutTestResult.PageLayout actualLayout, LayoutTestResult.PageLayout expectedLayout)
  44. {
  45. foreach (var expectedMock in expectedLayout.Mocks)
  46. {
  47. var matchingActualMock = actualLayout
  48. .Mocks
  49. .Where(x => x.MockId == expectedMock.MockId)
  50. .Where(x => Position.Equal(x.Position, expectedMock.Position))
  51. .Where(x => Size.Equal(x.Size, expectedMock.Size))
  52. .Count();
  53. if (matchingActualMock == 0)
  54. throw new Exception($"Cannot find '{expectedMock.MockId}' mock on position {expectedMock.Position} and size {expectedMock.Size}");
  55. if (matchingActualMock > 1)
  56. throw new Exception($"Found multiple '{expectedMock.MockId}' mocks on position {expectedMock.Position} and size {expectedMock.Size}");
  57. }
  58. }
  59. static void ValidateDrawingOrder(LayoutTestResult.PageLayout actualLayout, LayoutTestResult.PageLayout expectedLayout)
  60. {
  61. var actualOverlaps = actualLayout.Mocks.GetOverlappingItems().ToList();
  62. var expectedOverlaps = expectedLayout.Mocks.GetOverlappingItems().ToList();
  63. foreach (var expectedOverlap in expectedOverlaps)
  64. {
  65. var matchingActualElements = actualOverlaps.Count(actualOverlap => actualOverlap.belowMockId == expectedOverlap.belowMockId && actualOverlap.aboveMockId == expectedOverlap.aboveMockId);
  66. if (matchingActualElements != 1)
  67. throw new Exception($"Mock '{expectedOverlap.belowMockId}' should be visible below '{expectedOverlap.aboveMockId}' mock");
  68. }
  69. }
  70. }
  71. }