LineCanvasTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. namespace Terminal.Gui.DrawingTests;
  2. /// <summary>
  3. /// Tests for <see cref="LineCanvas"/>. All tests are parallelizable as they test LineCanvas directly
  4. /// without requiring Application.Driver or global state.
  5. /// </summary>
  6. public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase
  7. {
  8. #region Add_2_Lines Tests - Line Intersection Tests
  9. [Theory]
  10. // Horizontal lines with a vertical zero-length
  11. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, 0, 0, 0, Orientation.Vertical, LineStyle.Single, "╞")]
  12. [InlineData (0, 0, -1, Orientation.Horizontal, LineStyle.Double, 0, 0, 0, Orientation.Vertical, LineStyle.Single, "╡")]
  13. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╟")]
  14. [InlineData (0, 0, -1, Orientation.Horizontal, LineStyle.Single, 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╢")]
  15. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, 0, 0, 0, Orientation.Vertical, LineStyle.Single, "├")]
  16. [InlineData (0, 0, -1, Orientation.Horizontal, LineStyle.Single, 0, 0, 0, Orientation.Vertical, LineStyle.Single, "┤")]
  17. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╠")]
  18. [InlineData (0, 0, -1, Orientation.Horizontal, LineStyle.Double, 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╣")]
  19. // Vertical lines with a horizontal zero-length
  20. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, 0, 0, 1, Orientation.Vertical, LineStyle.Single, "╥")]
  21. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, 0, 0, -1, Orientation.Vertical, LineStyle.Single, "╨")]
  22. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, 0, 0, 1, Orientation.Vertical, LineStyle.Double, "╤")]
  23. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, 0, 0, -1, Orientation.Vertical, LineStyle.Double, "╧")]
  24. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, 0, 0, 1, Orientation.Vertical, LineStyle.Single, "┬")]
  25. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, 0, 0, -1, Orientation.Vertical, LineStyle.Single, "┴")]
  26. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, 0, 0, 1, Orientation.Vertical, LineStyle.Double, "╦")]
  27. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, 0, 0, -1, Orientation.Vertical, LineStyle.Double, "╩")]
  28. // Both zero-length (cross)
  29. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┼")]
  30. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╫")]
  31. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╪")]
  32. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╬")]
  33. public void Add_2_Lines_Creates_Correct_Intersection (
  34. int x1,
  35. int y1,
  36. int len1,
  37. Orientation o1,
  38. LineStyle s1,
  39. int x2,
  40. int y2,
  41. int len2,
  42. Orientation o2,
  43. LineStyle s2,
  44. string expected
  45. )
  46. {
  47. var canvas = new LineCanvas ();
  48. canvas.AddLine (new Point (x1, y1), len1, o1, s1);
  49. canvas.AddLine (new Point (x2, y2), len2, o2, s2);
  50. string actual = canvas.ToString ();
  51. Assert.Equal (expected, actual);
  52. }
  53. #endregion
  54. #region Length Tests
  55. [Theory]
  56. [InlineData (0, 0, Orientation.Horizontal, "─")]
  57. [InlineData (1, 0, Orientation.Horizontal, "─")]
  58. [InlineData (0, 1, Orientation.Horizontal, "─")]
  59. [InlineData (-1, 0, Orientation.Horizontal, "─")]
  60. [InlineData (0, -1, Orientation.Horizontal, "─")]
  61. [InlineData (-1, -1, Orientation.Horizontal, "─")]
  62. [InlineData (0, 0, Orientation.Vertical, "│")]
  63. [InlineData (1, 0, Orientation.Vertical, "│")]
  64. [InlineData (0, 1, Orientation.Vertical, "│")]
  65. [InlineData (0, -1, Orientation.Vertical, "│")]
  66. [InlineData (-1, 0, Orientation.Vertical, "│")]
  67. [InlineData (-1, -1, Orientation.Vertical, "│")]
  68. public void Length_0_Creates_Single_Character_Line (int x, int y, Orientation orientation, string expected)
  69. {
  70. var canvas = new LineCanvas ();
  71. canvas.AddLine (new Point (x, y), 0, orientation, LineStyle.Single);
  72. string actual = canvas.ToString ();
  73. Assert.Equal (expected, actual);
  74. }
  75. [Theory]
  76. [InlineData (0, 0, 1, Orientation.Horizontal, "─")]
  77. [InlineData (1, 0, 1, Orientation.Horizontal, "─")]
  78. [InlineData (0, 1, 1, Orientation.Horizontal, "─")]
  79. [InlineData (0, 0, 1, Orientation.Vertical, "│")]
  80. [InlineData (1, 0, 1, Orientation.Vertical, "│")]
  81. [InlineData (0, 1, 1, Orientation.Vertical, "│")]
  82. [InlineData (-1, 0, 1, Orientation.Horizontal, "─")]
  83. [InlineData (0, -1, 1, Orientation.Horizontal, "─")]
  84. [InlineData (-1, 0, 1, Orientation.Vertical, "│")]
  85. [InlineData (0, -1, 1, Orientation.Vertical, "│")]
  86. [InlineData (0, 0, 2, Orientation.Horizontal, "──")]
  87. [InlineData (0, 0, 3, Orientation.Horizontal, "───")]
  88. [InlineData (0, 0, 2, Orientation.Vertical, "│\n│")]
  89. [InlineData (0, 0, 3, Orientation.Vertical, "│\n│\n│")]
  90. public void Length_n_Creates_Line_Of_Length_n (int x, int y, int length, Orientation orientation, string expected)
  91. {
  92. var canvas = new LineCanvas ();
  93. canvas.AddLine (new Point (x, y), length, orientation, LineStyle.Single);
  94. string actual = canvas.ToString ();
  95. Assert.Equal (expected, actual);
  96. }
  97. [Fact]
  98. public void Length_Negative_Creates_Line_In_Opposite_Direction ()
  99. {
  100. var canvas = new LineCanvas ();
  101. // Add a horizontal line from (2, 0) going left (negative length)
  102. canvas.AddLine (new Point (2, 0), -3, Orientation.Horizontal, LineStyle.Single);
  103. string actual = canvas.ToString ();
  104. Assert.Equal ("───", actual);
  105. }
  106. [Theory]
  107. [InlineData (Orientation.Horizontal, "─")]
  108. [InlineData (Orientation.Vertical, "│")]
  109. public void Length_Zero_Alone_Creates_Single_Line (Orientation orientation, string expected)
  110. {
  111. var canvas = new LineCanvas ();
  112. canvas.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  113. string actual = canvas.ToString ();
  114. Assert.Equal (expected, actual);
  115. }
  116. [Theory]
  117. [InlineData (Orientation.Horizontal, "┼")]
  118. [InlineData (Orientation.Vertical, "┼")]
  119. public void Length_Zero_Cross_Creates_Intersection (Orientation orientation, string expected)
  120. {
  121. var canvas = new LineCanvas ();
  122. canvas.AddLine (new Point (0, 0), 0, Orientation.Horizontal, LineStyle.Single);
  123. canvas.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  124. string actual = canvas.ToString ();
  125. Assert.Equal (expected, actual);
  126. }
  127. [Theory]
  128. [InlineData (Orientation.Horizontal, "┬")]
  129. [InlineData (Orientation.Vertical, "├")]
  130. public void Length_Zero_NextTo_Opposite_Creates_T (Orientation orientation, string expected)
  131. {
  132. var canvas = new LineCanvas ();
  133. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, LineStyle.Single);
  134. canvas.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  135. string actual = canvas.ToString ();
  136. Assert.Equal (expected, actual);
  137. }
  138. #endregion
  139. #region ToString Tests
  140. [Fact]
  141. public void ToString_Empty_Canvas_Returns_Empty_String ()
  142. {
  143. var canvas = new LineCanvas ();
  144. Assert.Equal (string.Empty, canvas.ToString ());
  145. }
  146. [Theory]
  147. [InlineData (0, 0, "─")]
  148. [InlineData (1, 0, " ─")]
  149. [InlineData (0, 1, "\n─")]
  150. [InlineData (1, 1, "\n ─")]
  151. [InlineData (2, 0, " ─")]
  152. [InlineData (2, 1, "\n ─")]
  153. [InlineData (0, 2, "\n\n─")]
  154. [InlineData (2, 2, "\n\n ─")]
  155. public void ToString_Positive_Horizontal_1Line_With_Offset (int x, int y, string expected)
  156. {
  157. var canvas = new LineCanvas ();
  158. canvas.AddLine (new Point (x, y), 1, Orientation.Horizontal, LineStyle.Single);
  159. string actual = canvas.ToString ();
  160. Assert.Equal (expected, actual);
  161. }
  162. [Theory]
  163. [InlineData (0, 0, "│")]
  164. [InlineData (1, 0, " │")]
  165. [InlineData (0, 1, "\n│")]
  166. [InlineData (1, 1, "\n │")]
  167. [InlineData (2, 0, " │")]
  168. [InlineData (2, 1, "\n │")]
  169. [InlineData (0, 2, "\n\n│")]
  170. [InlineData (2, 2, "\n\n │")]
  171. public void ToString_Positive_Vertical_1Line_With_Offset (int x, int y, string expected)
  172. {
  173. var canvas = new LineCanvas ();
  174. canvas.AddLine (new Point (x, y), 1, Orientation.Vertical, LineStyle.Single);
  175. string actual = canvas.ToString ();
  176. Assert.Equal (expected, actual);
  177. }
  178. #endregion
  179. #region Bounds Tests
  180. [Fact]
  181. public void Bounds_Empty_Canvas_Returns_Empty_Rectangle ()
  182. {
  183. var canvas = new LineCanvas ();
  184. Assert.Equal (Rectangle.Empty, canvas.Bounds);
  185. }
  186. [Fact]
  187. public void Bounds_Single_Point_Returns_1x1_Rectangle ()
  188. {
  189. var canvas = new LineCanvas ();
  190. canvas.AddLine (new Point (5, 5), 0, Orientation.Horizontal, LineStyle.Single);
  191. Assert.Equal (new Rectangle (5, 5, 1, 1), canvas.Bounds);
  192. }
  193. [Fact]
  194. public void Bounds_Horizontal_Line_Returns_Correct_Rectangle ()
  195. {
  196. var canvas = new LineCanvas ();
  197. canvas.AddLine (new Point (2, 3), 5, Orientation.Horizontal, LineStyle.Single);
  198. Assert.Equal (new Rectangle (2, 3, 5, 1), canvas.Bounds);
  199. }
  200. [Fact]
  201. public void Bounds_Vertical_Line_Returns_Correct_Rectangle ()
  202. {
  203. var canvas = new LineCanvas ();
  204. canvas.AddLine (new Point (2, 3), 5, Orientation.Vertical, LineStyle.Single);
  205. Assert.Equal (new Rectangle (2, 3, 1, 5), canvas.Bounds);
  206. }
  207. [Fact]
  208. public void Bounds_Multiple_Lines_Returns_Union ()
  209. {
  210. var canvas = new LineCanvas ();
  211. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  212. canvas.AddLine (new Point (0, 0), 3, Orientation.Vertical, LineStyle.Single);
  213. Assert.Equal (new Rectangle (0, 0, 5, 3), canvas.Bounds);
  214. }
  215. [Fact]
  216. public void Bounds_Negative_Length_Included ()
  217. {
  218. var canvas = new LineCanvas ();
  219. canvas.AddLine (new Point (5, 5), -3, Orientation.Horizontal, LineStyle.Single);
  220. Assert.Equal (new Rectangle (2, 5, 3, 1), canvas.Bounds);
  221. }
  222. #endregion
  223. #region Lines Property Tests
  224. [Fact]
  225. public void Lines_Empty_Canvas_Returns_Empty_Collection ()
  226. {
  227. var canvas = new LineCanvas ();
  228. Assert.Empty (canvas.Lines);
  229. }
  230. [Fact]
  231. public void Lines_Returns_Added_Lines ()
  232. {
  233. var canvas = new LineCanvas ();
  234. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  235. canvas.AddLine (new Point (0, 0), 3, Orientation.Vertical, LineStyle.Double);
  236. Assert.Equal (2, canvas.Lines.Count);
  237. }
  238. [Fact]
  239. public void Lines_Is_ReadOnly ()
  240. {
  241. var canvas = new LineCanvas ();
  242. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  243. Assert.IsAssignableFrom<IReadOnlyCollection<StraightLine>> (canvas.Lines);
  244. }
  245. #endregion
  246. #region GetMap Tests
  247. [Fact]
  248. public void GetMap_Empty_Canvas_Returns_Empty_Dictionary ()
  249. {
  250. var canvas = new LineCanvas ();
  251. var map = canvas.GetMap ();
  252. Assert.Empty (map);
  253. }
  254. [Fact]
  255. public void GetMap_Single_Line_Returns_Correct_Points ()
  256. {
  257. var canvas = new LineCanvas ();
  258. canvas.AddLine (new Point (0, 0), 3, Orientation.Horizontal, LineStyle.Single);
  259. var map = canvas.GetMap ();
  260. Assert.Equal (3, map.Count);
  261. Assert.True (map.ContainsKey (new Point (0, 0)));
  262. Assert.True (map.ContainsKey (new Point (1, 0)));
  263. Assert.True (map.ContainsKey (new Point (2, 0)));
  264. }
  265. [Fact]
  266. public void GetMap_Returns_Correct_Runes ()
  267. {
  268. var canvas = new LineCanvas ();
  269. canvas.AddLine (new Point (0, 0), 3, Orientation.Horizontal, LineStyle.Single);
  270. var map = canvas.GetMap ();
  271. Assert.Equal (new System.Text.Rune ('─'), map [new Point (0, 0)]);
  272. Assert.Equal (new System.Text.Rune ('─'), map [new Point (1, 0)]);
  273. Assert.Equal (new System.Text.Rune ('─'), map [new Point (2, 0)]);
  274. }
  275. #endregion
  276. #region Clear Tests
  277. [Fact]
  278. public void Clear_Removes_All_Lines ()
  279. {
  280. var canvas = new LineCanvas ();
  281. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  282. canvas.AddLine (new Point (0, 0), 3, Orientation.Vertical, LineStyle.Single);
  283. canvas.Clear ();
  284. Assert.Empty (canvas.Lines);
  285. Assert.Equal (Rectangle.Empty, canvas.Bounds);
  286. Assert.Empty (canvas.GetMap ());
  287. }
  288. #endregion
  289. #region AddLine Tests
  290. [Fact]
  291. public void AddLine_Adds_Line_To_Canvas ()
  292. {
  293. var canvas = new LineCanvas ();
  294. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  295. Assert.Single (canvas.Lines);
  296. }
  297. [Fact]
  298. public void AddLine_Multiple_Times_Adds_All_Lines ()
  299. {
  300. var canvas = new LineCanvas ();
  301. canvas.AddLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single);
  302. canvas.AddLine (new Point (0, 1), 5, Orientation.Horizontal, LineStyle.Single);
  303. canvas.AddLine (new Point (0, 2), 5, Orientation.Horizontal, LineStyle.Single);
  304. Assert.Equal (3, canvas.Lines.Count);
  305. }
  306. #endregion
  307. #region Constructor Tests
  308. [Fact]
  309. public void Constructor_Creates_Empty_Canvas ()
  310. {
  311. var canvas = new LineCanvas ();
  312. Assert.Empty (canvas.Lines);
  313. Assert.Equal (Rectangle.Empty, canvas.Bounds);
  314. }
  315. [Fact]
  316. public void Constructor_With_Lines_Creates_Canvas_With_Lines ()
  317. {
  318. var lines = new[]
  319. {
  320. new StraightLine (new Point (0, 0), 5, Orientation.Horizontal, LineStyle.Single),
  321. new StraightLine (new Point (0, 0), 3, Orientation.Vertical, LineStyle.Single)
  322. };
  323. var canvas = new LineCanvas (lines);
  324. Assert.Equal (2, canvas.Lines.Count);
  325. }
  326. #endregion
  327. }