TestPlan.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text.Json;
  4. using FluentAssertions;
  5. using NUnit.Framework;
  6. using QuestPDF.Drawing;
  7. using QuestPDF.Elements;
  8. using QuestPDF.Helpers;
  9. using QuestPDF.Infrastructure;
  10. using QuestPDF.UnitTests.TestEngine.Operations;
  11. namespace QuestPDF.UnitTests.TestEngine
  12. {
  13. internal class TestPlan
  14. {
  15. private const string DefaultChildName = "child";
  16. private static Random Random { get; } = new Random();
  17. private Element Element { get; set; }
  18. private ICanvas Canvas { get; }
  19. private Size OperationInput { get; set; }
  20. private Queue<OperationBase> Operations { get; } = new Queue<OperationBase>();
  21. public TestPlan()
  22. {
  23. Canvas = CreateCanvas();
  24. }
  25. public static TestPlan For(Func<TestPlan, Element> create)
  26. {
  27. var plan = new TestPlan();
  28. plan.Element = create(plan);
  29. return plan;
  30. }
  31. private T GetExpected<T>() where T : OperationBase
  32. {
  33. if (Operations.TryDequeue(out var value) && value is T result)
  34. return result;
  35. var gotType = value?.GetType()?.Name ?? "null";
  36. Assert.Fail($"Expected: {typeof(T).Name}, got {gotType}: {JsonSerializer.Serialize(value)}");
  37. return null;
  38. }
  39. private ICanvas CreateCanvas()
  40. {
  41. return new MockCanvas
  42. {
  43. TranslateFunc = position =>
  44. {
  45. var expected = GetExpected<CanvasTranslateOperation>();
  46. Assert.AreEqual(expected.Position.X, position.X, "Translate X");
  47. Assert.AreEqual(expected.Position.Y, position.Y, "Translate Y");
  48. },
  49. RotateFunc = angle =>
  50. {
  51. var expected = GetExpected<CanvasRotateOperation>();
  52. Assert.AreEqual(expected.Angle, angle, "Rotate angle");
  53. },
  54. ScaleFunc = (scaleX, scaleY) =>
  55. {
  56. var expected = GetExpected<CanvasScaleOperation>();
  57. Assert.AreEqual(expected.ScaleX, scaleX, "Scale X");
  58. Assert.AreEqual(expected.ScaleY, scaleY, "Scale Y");
  59. },
  60. DrawFilledRectangleFunc = (position, size, color) =>
  61. {
  62. var expected = GetExpected<CanvasDrawFilledRectangleOperation>();
  63. Assert.AreEqual(expected.Position.X, position.X, "Draw filled rectangle: X");
  64. Assert.AreEqual(expected.Position.Y, position.Y, "Draw filled rectangle: Y");
  65. Assert.AreEqual(expected.Size.Width, size.Width, "Draw filled rectangle: width");
  66. Assert.AreEqual(expected.Size.Height, size.Height, "Draw filled rectangle: height");
  67. Assert.AreEqual(expected.Color, color, "Draw filled rectangle: color");
  68. },
  69. DrawStrokedRectangleFunc = (size, color, width) =>
  70. {
  71. var expected = GetExpected<CanvasDrawStrokedRectangleOperation>();
  72. Assert.AreEqual(expected.Size.Width, size.Width, "Draw stroked rectangle: width");
  73. Assert.AreEqual(expected.Size.Height, size.Height, "Draw stroked rectangle: height");
  74. Assert.AreEqual(expected.Color, color, "Draw stroked rectangle: color");
  75. Assert.AreEqual(expected.Width, width, "Draw stroked rectangle: width");
  76. },
  77. DrawTextFunc = (text, position, style) =>
  78. {
  79. var expected = GetExpected<CanvasDrawTextOperation>();
  80. Assert.AreEqual(expected.Text, text);
  81. Assert.AreEqual(expected.Position.X, position.X, "Draw text: X");
  82. Assert.AreEqual(expected.Position.Y, position.Y, "Draw text: Y");
  83. Assert.AreEqual(expected.Style.Color, style.Color, "Draw text: color");
  84. Assert.AreEqual(expected.Style.FontType, style.FontType, "Draw text: font");
  85. Assert.AreEqual(expected.Style.Size, style.Size, "Draw text: size");
  86. },
  87. DrawImageFunc = (image, position, size) =>
  88. {
  89. var expected = GetExpected<CanvasDrawImageOperation>();
  90. Assert.AreEqual(expected.Position.X, position.X, "Draw image: X");
  91. Assert.AreEqual(expected.Position.Y, position.Y, "Draw image: Y");
  92. Assert.AreEqual(expected.Size.Width, size.Width, "Draw image: width");
  93. Assert.AreEqual(expected.Size.Height, size.Height, "Draw image: height");
  94. }
  95. };
  96. }
  97. public Element CreateChild() => CreateChild(DefaultChildName);
  98. public Element CreateChild(string id)
  99. {
  100. return new ElementMock
  101. {
  102. Id = id,
  103. MeasureFunc = availableSpace =>
  104. {
  105. var expected = GetExpected<ChildMeasureOperation>();
  106. Assert.AreEqual(expected.ChildId, id);
  107. Assert.AreEqual(expected.Input.Width, availableSpace.Width, $"Measure: width of child '{expected.ChildId}'");
  108. Assert.AreEqual(expected.Input.Height, availableSpace.Height, $"Measure: height of child '{expected.ChildId}'");
  109. return expected.Output;
  110. },
  111. DrawFunc = availableSpace =>
  112. {
  113. var expected = GetExpected<ChildDrawOperation>();
  114. Assert.AreEqual(expected.ChildId, id);
  115. Assert.AreEqual(expected.Input.Width, availableSpace.Width, $"Draw: width of child '{expected.ChildId}'");
  116. Assert.AreEqual(expected.Input.Height, availableSpace.Height, $"Draw: width of child '{expected.ChildId}'");
  117. }
  118. };
  119. }
  120. public TestPlan MeasureElement(Size input)
  121. {
  122. OperationInput = input;
  123. return this;
  124. }
  125. public TestPlan DrawElement(Size input)
  126. {
  127. OperationInput = input;
  128. return this;
  129. }
  130. private TestPlan AddOperation(OperationBase operationBase)
  131. {
  132. Operations.Enqueue(operationBase);
  133. return this;
  134. }
  135. public TestPlan ExpectChildMeasure(Size expectedInput, SpacePlan returns)
  136. {
  137. return ExpectChildMeasure(DefaultChildName, expectedInput, returns);
  138. }
  139. public TestPlan ExpectChildMeasure(string child, Size expectedInput, SpacePlan returns)
  140. {
  141. return AddOperation(new ChildMeasureOperation(child, expectedInput, returns));
  142. }
  143. public TestPlan ExpectChildDraw(Size expectedInput)
  144. {
  145. return ExpectChildDraw(DefaultChildName, expectedInput);
  146. }
  147. public TestPlan ExpectChildDraw(string child, Size expectedInput)
  148. {
  149. return AddOperation(new ChildDrawOperation(child, expectedInput));
  150. }
  151. public TestPlan ExpectCanvasTranslate(Position position)
  152. {
  153. return AddOperation(new CanvasTranslateOperation(position));
  154. }
  155. public TestPlan ExpectCanvasTranslate(float left, float top)
  156. {
  157. return AddOperation(new CanvasTranslateOperation(new Position(left, top)));
  158. }
  159. public TestPlan ExpectCanvasScale(float scaleX, float scaleY)
  160. {
  161. return AddOperation(new CanvasScaleOperation(scaleX, scaleY));
  162. }
  163. public TestPlan ExpectCanvasRotate(float angle)
  164. {
  165. return AddOperation(new CanvasRotateOperation(angle));
  166. }
  167. public TestPlan ExpectCanvasDrawFilledRectangle(Position position, Size size, string color)
  168. {
  169. return AddOperation(new CanvasDrawFilledRectangleOperation(position, size, color));
  170. }
  171. public TestPlan ExpectCanvasDrawStrokedRectangle(Size size, string color, float width)
  172. {
  173. return AddOperation(new CanvasDrawStrokedRectangleOperation(size, color, width));
  174. }
  175. public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
  176. {
  177. return AddOperation(new CanvasDrawTextOperation(text, position, style));
  178. }
  179. public TestPlan ExpectCanvasDrawImage(Position position, Size size)
  180. {
  181. return AddOperation(new CanvasDrawImageOperation(position, size));
  182. }
  183. public TestPlan CheckMeasureResult(SpacePlan expected)
  184. {
  185. Element.HandleVisitor(x => x?.Initialize(null, Canvas));
  186. var actual = Element.Measure(OperationInput);
  187. Assert.AreEqual(expected.GetType(), actual.GetType());
  188. Assert.AreEqual(expected.Width, actual.Width, "Measure: width");
  189. Assert.AreEqual(expected.Height, actual.Height, "Measure: height");
  190. Assert.AreEqual(expected.Type, actual.Type, "Measure: height");
  191. return this;
  192. }
  193. public TestPlan CheckDrawResult()
  194. {
  195. Element.HandleVisitor(x => x?.Initialize(null, Canvas));
  196. Element.Draw(OperationInput);
  197. return this;
  198. }
  199. public TestPlan CheckState(Func<Element, bool> condition)
  200. {
  201. Assert.IsTrue(condition(Element), "Checking condition");
  202. return this;
  203. }
  204. public TestPlan CheckState<T>(Func<T, bool> condition) where T : Element
  205. {
  206. Assert.IsTrue(Element is T);
  207. Assert.IsTrue(condition(Element as T), "Checking condition");
  208. return this;
  209. }
  210. public static Element CreateUniqueElement()
  211. {
  212. return new Constrained
  213. {
  214. MinWidth = 90,
  215. MinHeight = 60,
  216. Child = new DynamicImage
  217. {
  218. Source = Placeholders.Image
  219. }
  220. };
  221. }
  222. public static void CompareOperations(Element value, Element expected, Size? availableSpace = null)
  223. {
  224. CompareMeasureOperations(value, expected, availableSpace);
  225. CompareDrawOperations(value, expected, availableSpace);
  226. }
  227. private static void CompareMeasureOperations(Element value, Element expected, Size? availableSpace = null)
  228. {
  229. availableSpace ??= new Size(400, 300);
  230. var canvas = new FreeCanvas();
  231. value.HandleVisitor(x => x.Initialize(null, canvas));
  232. var valueMeasure = value.Measure(availableSpace.Value);
  233. expected.HandleVisitor(x => x.Initialize(null, canvas));
  234. var expectedMeasure = expected.Measure(availableSpace.Value);
  235. valueMeasure.Should().BeEquivalentTo(expectedMeasure);
  236. }
  237. private static void CompareDrawOperations(Element value, Element expected, Size? availableSpace = null)
  238. {
  239. availableSpace ??= new Size(400, 300);
  240. var valueCanvas = new OperationRecordingCanvas();
  241. value.HandleVisitor(x => x.Initialize(null, valueCanvas));
  242. value.Draw(availableSpace.Value);
  243. var expectedCanvas = new OperationRecordingCanvas();
  244. expected.HandleVisitor(x => x.Initialize(null, expectedCanvas));
  245. expected.Draw(availableSpace.Value);
  246. valueCanvas.Operations.Should().BeEquivalentTo(expectedCanvas.Operations);
  247. }
  248. }
  249. }