LineCanvasTests.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Xunit;
  5. using Xunit.Abstractions;
  6. namespace Terminal.Gui.DrawingTests {
  7. public class LineCanvasTests {
  8. readonly ITestOutputHelper output;
  9. public LineCanvasTests (ITestOutputHelper output)
  10. {
  11. this.output = output;
  12. }
  13. [InlineData (0, 0, 0,
  14. 0, 0, 1, 1)]
  15. [InlineData (0, 0, 1,
  16. 0, 0, 1, 1)]
  17. [InlineData (0, 0, 2,
  18. 0, 0, 2, 1)]
  19. [InlineData (0, 0, 3,
  20. 0, 0, 3, 1)]
  21. [InlineData (0, 0, -1,
  22. 0, 0, 1, 1)]
  23. [InlineData (0, 0, -2,
  24. -1, 0, 2, 1)]
  25. [InlineData (0, 0, -3,
  26. -2, 0, 3, 1)]
  27. [Theory, SetupFakeDriver]
  28. public void Bounds_H_Line (int x, int y, int length,
  29. int expectedX, int expectedY, int expectedWidth, int expectedHeight)
  30. {
  31. var canvas = new LineCanvas ();
  32. canvas.AddLine (new Point (x, y), length, Orientation.Horizontal, LineStyle.Single);
  33. Assert.Equal (new Rect (expectedX, expectedY, expectedWidth, expectedHeight), canvas.Bounds);
  34. }
  35. [InlineData (0, 0, 0,
  36. 0, 0, 1, 1)]
  37. [InlineData (0, 0, 1,
  38. 0, 0, 1, 1)]
  39. [InlineData (0, 0, 2,
  40. 0, 0, 2, 2)]
  41. [InlineData (0, 0, 3,
  42. 0, 0, 3, 3)]
  43. [InlineData (0, 0, -1,
  44. 0, 0, 1, 1)]
  45. [InlineData (0, 0, -2,
  46. -1, -1, 2, 2)]
  47. [InlineData (0, 0, -3,
  48. -2, -2, 3, 3)]
  49. [Theory, SetupFakeDriver]
  50. public void Bounds_H_And_V_Lines_Both_Positive (int x, int y, int length,
  51. int expectedX, int expectedY, int expectedWidth, int expectedHeight)
  52. {
  53. var canvas = new LineCanvas ();
  54. canvas.AddLine (new Point (x, y), length, Orientation.Horizontal, LineStyle.Single);
  55. canvas.AddLine (new Point (x, y), length, Orientation.Vertical, LineStyle.Single);
  56. Assert.Equal (new Rect (expectedX, expectedY, expectedWidth, expectedHeight), canvas.Bounds);
  57. }
  58. [Fact, SetupFakeDriver]
  59. public void Canvas_Updates_On_Changes ()
  60. {
  61. var lc = new LineCanvas ();
  62. Assert.Equal (Rect.Empty, lc.Bounds);
  63. lc.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Double);
  64. Assert.NotEqual (Rect.Empty, lc.Bounds);
  65. lc.Clear ();
  66. Assert.Equal (Rect.Empty, lc.Bounds);
  67. }
  68. [Fact, SetupFakeDriver]
  69. public void Bounds_Specific ()
  70. {
  71. // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1)
  72. // This proves we aren't drawing excess above
  73. int x = 1;
  74. int y = 2;
  75. int width = 3;
  76. int height = 2;
  77. var lc = new LineCanvas ();
  78. // 01230
  79. // ╔╡╞╗1
  80. // ║ ║2
  81. // Add a short horiz line for ╔╡
  82. lc.AddLine (new Point (x, y), 2, Orientation.Horizontal, LineStyle.Double);
  83. Assert.Equal (new Rect (x, y, 2, 1), lc.Bounds);
  84. //LHS line down
  85. lc.AddLine (new Point (x, y), height, Orientation.Vertical, LineStyle.Double);
  86. Assert.Equal (new Rect (x, y, 2, 2), lc.Bounds);
  87. //Vertical line before Title, results in a ╡
  88. lc.AddLine (new Point (x + 1, y), 0, Orientation.Vertical, LineStyle.Single);
  89. Assert.Equal (new Rect (x, y, 2, 2), lc.Bounds);
  90. //Vertical line after Title, results in a ╞
  91. lc.AddLine (new Point (x + 2, y), 0, Orientation.Vertical, LineStyle.Single);
  92. Assert.Equal (new Rect (x, y, 3, 2), lc.Bounds);
  93. // remainder of top line
  94. lc.AddLine (new Point (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double);
  95. Assert.Equal (new Rect (x, y, 4, 2), lc.Bounds);
  96. //RHS line down
  97. lc.AddLine (new Point (x + width, y), height, Orientation.Vertical, LineStyle.Double);
  98. Assert.Equal (new Rect (x, y, 4, 2), lc.Bounds);
  99. TestHelpers.AssertEqual (output, @"
  100. ╔╡╞╗
  101. ║ ║",
  102. $"{Environment.NewLine}{lc}");
  103. }
  104. [Fact, SetupFakeDriver]
  105. public void Bounds_Specific_With_Ustring ()
  106. {
  107. // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1)
  108. // This proves we aren't drawing excess above
  109. int x = 1;
  110. int y = 2;
  111. int width = 3;
  112. int height = 2;
  113. var lc = new LineCanvas ();
  114. // 01230
  115. // ╔╡╞╗1
  116. // ║ ║2
  117. // Add a short horiz line for ╔╡
  118. lc.AddLine (new Point (x, y), 2, Orientation.Horizontal, LineStyle.Double);
  119. Assert.Equal (new Rect (x, y, 2, 1), lc.Bounds);
  120. //LHS line down
  121. lc.AddLine (new Point (x, y), height, Orientation.Vertical, LineStyle.Double);
  122. Assert.Equal (new Rect (x, y, 2, 2), lc.Bounds);
  123. //Vertical line before Title, results in a ╡
  124. lc.AddLine (new Point (x + 1, y), 0, Orientation.Vertical, LineStyle.Single);
  125. Assert.Equal (new Rect (x, y, 2, 2), lc.Bounds);
  126. //Vertical line after Title, results in a ╞
  127. lc.AddLine (new Point (x + 2, y), 0, Orientation.Vertical, LineStyle.Single);
  128. Assert.Equal (new Rect (x, y, 3, 2), lc.Bounds);
  129. // remainder of top line
  130. lc.AddLine (new Point (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double);
  131. Assert.Equal (new Rect (x, y, 4, 2), lc.Bounds);
  132. //RHS line down
  133. lc.AddLine (new Point (x + width, y), height, Orientation.Vertical, LineStyle.Double);
  134. Assert.Equal (new Rect (x, y, 4, 2), lc.Bounds);
  135. TestHelpers.AssertEqual (output, @"
  136. ╔╡╞╗
  137. ║ ║",
  138. $"{Environment.NewLine}{lc}");
  139. }
  140. [Fact, SetupFakeDriver]
  141. public void ToString_Empty ()
  142. {
  143. var lc = new LineCanvas ();
  144. TestHelpers.AssertEqual (output, string.Empty, lc.ToString ());
  145. }
  146. // 012
  147. [InlineData (0, 0, "═══")]
  148. [InlineData (1, 0, "═══")]
  149. [InlineData (0, 1, "═══")]
  150. [InlineData (1, 1, "═══")]
  151. [InlineData (2, 2, "═══")]
  152. [InlineData (-1, 0, "═══")]
  153. [InlineData (0, -1, "═══")]
  154. [InlineData (-1, -1, "═══")]
  155. [InlineData (-2, -2, "═══")]
  156. [Theory, SetupFakeDriver]
  157. public void ToString_Positive_Horizontal_1Line_Offset (int x, int y, string expected)
  158. {
  159. var lc = new LineCanvas ();
  160. lc.AddLine (new Point (x, y), 3, Orientation.Horizontal, LineStyle.Double);
  161. TestHelpers.AssertEqual (output, expected, $"{lc}");
  162. }
  163. [InlineData (0, 0, 0, 0, "═══")]
  164. [InlineData (1, 0, 1, 0, "═══")]
  165. [InlineData (-1, 0, -1, 0, "═══")]
  166. [InlineData (0, 0, 1, 0, "════")]
  167. [InlineData (1, 0, 3, 0, "═════")]
  168. [InlineData (1, 0, 4, 0, "══════")]
  169. [InlineData (1, 0, 5, 0, "═══ ═══")]
  170. [InlineData (0, 0, 0, 1, $"═══\r\n═══")]
  171. [InlineData (0, 0, 1, 1, "═══ \r\n ═══")]
  172. [InlineData (0, 0, 2, 1, "═══ \r\n ═══")]
  173. [InlineData (1, 0, 0, 1, " ═══\r\n═══ ")]
  174. [InlineData (0, 1, 0, 1, "═══")]
  175. [InlineData (1, 1, 0, 1, "════")]
  176. [InlineData (2, 2, 0, 1, "═══ \r\n ═══")]
  177. [Theory, SetupFakeDriver]
  178. public void ToString_Positive_Horizontal_2Line_Offset (int x1, int y1, int x2, int y2, string expected)
  179. {
  180. var lc = new LineCanvas ();
  181. lc.AddLine (new Point (x1, y1), 3, Orientation.Horizontal, LineStyle.Double);
  182. lc.AddLine (new Point (x2, y2), 3, Orientation.Horizontal, LineStyle.Double);
  183. TestHelpers.AssertEqual (output, expected, $"{lc}");
  184. }
  185. [InlineData (Orientation.Horizontal, "─")]
  186. [InlineData (Orientation.Vertical, "│")]
  187. [Theory, SetupFakeDriver]
  188. public void Length_Zero_Alone_Is_Line (Orientation orientation, string expected)
  189. {
  190. var lc = new LineCanvas ();
  191. // Add a line at 0, 0 that's has length of 0
  192. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  193. TestHelpers.AssertEqual (output, expected, $"{lc}");
  194. }
  195. [InlineData (Orientation.Horizontal, "┼")]
  196. [InlineData (Orientation.Vertical, "┼")]
  197. [Theory, SetupFakeDriver]
  198. public void Length_Zero_Cross_Is_Cross (Orientation orientation, string expected)
  199. {
  200. var lc = new LineCanvas ();
  201. // Add point at opposite orientation
  202. lc.AddLine (new Point (0, 0), 0, orientation == Orientation.Horizontal ? Orientation.Vertical : Orientation.Horizontal, LineStyle.Single);
  203. // Add a line at 0, 0 that's has length of 0
  204. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  205. TestHelpers.AssertEqual (output, expected, $"{lc}");
  206. }
  207. [InlineData (Orientation.Horizontal, "╥")]
  208. [InlineData (Orientation.Vertical, "╞")]
  209. [Theory, SetupFakeDriver]
  210. public void Length_Zero_NextTo_Opposite_Is_T (Orientation orientation, string expected)
  211. {
  212. var lc = new LineCanvas ();
  213. // Add line with length of 1 in opposite orientation starting at same location
  214. if (orientation == Orientation.Horizontal) {
  215. lc.AddLine (new Point (0, 0), 1, Orientation.Vertical, LineStyle.Double);
  216. } else {
  217. lc.AddLine (new Point (0, 0), 1, Orientation.Horizontal, LineStyle.Double);
  218. }
  219. // Add a line at 0, 0 that's has length of 0
  220. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  221. TestHelpers.AssertEqual (output, expected, $"{lc}");
  222. }
  223. [InlineData (0, 0, Orientation.Horizontal, "─")]
  224. [InlineData (1, 0, Orientation.Horizontal, "─")]
  225. [InlineData (0, 1, Orientation.Horizontal, "─")]
  226. [InlineData (-1, 0, Orientation.Horizontal, "─")]
  227. [InlineData (0, -1, Orientation.Horizontal, "─")]
  228. [InlineData (-1, -1, Orientation.Horizontal, "─")]
  229. [InlineData (0, 0, Orientation.Vertical, "│")]
  230. [InlineData (1, 0, Orientation.Vertical, "│")]
  231. [InlineData (0, 1, Orientation.Vertical, "│")]
  232. [InlineData (0, -1, Orientation.Vertical, "│")]
  233. [InlineData (-1, 0, Orientation.Vertical, "│")]
  234. [InlineData (-1, -1, Orientation.Vertical, "│")]
  235. [Theory, SetupFakeDriver]
  236. public void Length_0_Is_1_Long (int x, int y, Orientation orientation, string expected)
  237. {
  238. var canvas = new LineCanvas ();
  239. // Add a line at 5, 5 that's has length of 1
  240. canvas.AddLine (new Point (x, y), 1, orientation, LineStyle.Single);
  241. TestHelpers.AssertEqual (output, $"{expected}", $"{canvas}");
  242. }
  243. // X is offset by 2
  244. [InlineData (0, 0, 1, Orientation.Horizontal, "─")]
  245. [InlineData (1, 0, 1, Orientation.Horizontal, "─")]
  246. [InlineData (0, 1, 1, Orientation.Horizontal, "─")]
  247. [InlineData (0, 0, 1, Orientation.Vertical, "│")]
  248. [InlineData (1, 0, 1, Orientation.Vertical, "│")]
  249. [InlineData (0, 1, 1, Orientation.Vertical, "│")]
  250. [InlineData (-1, 0, 1, Orientation.Horizontal, "─")]
  251. [InlineData (0, -1, 1, Orientation.Horizontal, "─")]
  252. [InlineData (-1, 0, 1, Orientation.Vertical, "│")]
  253. [InlineData (0, -1, 1, Orientation.Vertical, "│")]
  254. [InlineData (0, 0, -1, Orientation.Horizontal, "─")]
  255. [InlineData (1, 0, -1, Orientation.Horizontal, "─")]
  256. [InlineData (0, 1, -1, Orientation.Horizontal, "─")]
  257. [InlineData (0, 0, -1, Orientation.Vertical, "│")]
  258. [InlineData (1, 0, -1, Orientation.Vertical, "│")]
  259. [InlineData (0, 1, -1, Orientation.Vertical, "│")]
  260. [InlineData (-1, 0, -1, Orientation.Horizontal, "─")]
  261. [InlineData (0, -1, -1, Orientation.Horizontal, "─")]
  262. [InlineData (-1, 0, -1, Orientation.Vertical, "│")]
  263. [InlineData (0, -1, -1, Orientation.Vertical, "│")]
  264. [InlineData (0, 0, 2, Orientation.Horizontal, "──")]
  265. [InlineData (1, 0, 2, Orientation.Horizontal, "──")]
  266. [InlineData (0, 1, 2, Orientation.Horizontal, "──")]
  267. [InlineData (1, 1, 2, Orientation.Horizontal, "──")]
  268. [InlineData (0, 0, 2, Orientation.Vertical, "│\r\n│")]
  269. [InlineData (1, 0, 2, Orientation.Vertical, "│\r\n│")]
  270. [InlineData (0, 1, 2, Orientation.Vertical, "│\r\n│")]
  271. [InlineData (1, 1, 2, Orientation.Vertical, "│\r\n│")]
  272. [InlineData (-1, 0, 2, Orientation.Horizontal, "──")]
  273. [InlineData (0, -1, 2, Orientation.Horizontal, "──")]
  274. [InlineData (-1, 0, 2, Orientation.Vertical, "│\r\n│")]
  275. [InlineData (0, -1, 2, Orientation.Vertical, "│\r\n│")]
  276. [InlineData (-1, -1, 2, Orientation.Vertical, "│\r\n│")]
  277. [InlineData (0, 0, -2, Orientation.Horizontal, "──")]
  278. [InlineData (1, 0, -2, Orientation.Horizontal, "──")]
  279. [InlineData (0, 1, -2, Orientation.Horizontal, "──")]
  280. [InlineData (0, 0, -2, Orientation.Vertical, "│\r\n│")]
  281. [InlineData (1, 0, -2, Orientation.Vertical, "│\r\n│")]
  282. [InlineData (0, 1, -2, Orientation.Vertical, "│\r\n│")]
  283. [InlineData (1, 1, -2, Orientation.Vertical, "│\r\n│")]
  284. [InlineData (-1, 0, -2, Orientation.Horizontal, "──")]
  285. [InlineData (0, -1, -2, Orientation.Horizontal, "──")]
  286. [InlineData (-1, 0, -2, Orientation.Vertical, "│\r\n│")]
  287. [InlineData (0, -1, -2, Orientation.Vertical, "│\r\n│")]
  288. [InlineData (-1, -1, -2, Orientation.Vertical, "│\r\n│")]
  289. [Theory, SetupFakeDriver]
  290. public void Length_n_Is_n_Long (int x, int y, int length, Orientation orientation, string expected)
  291. {
  292. var canvas = new LineCanvas ();
  293. canvas.AddLine (new Point (x, y), length, orientation, LineStyle.Single);
  294. var result = canvas.ToString ();
  295. TestHelpers.AssertEqual (output, expected, result);
  296. }
  297. [Fact, SetupFakeDriver]
  298. public void Length_Negative ()
  299. {
  300. var offset = new Point (5, 5);
  301. var canvas = new LineCanvas ();
  302. canvas.AddLine (offset, -3, Orientation.Horizontal, LineStyle.Single);
  303. string looksLike = "───";
  304. Assert.Equal (looksLike, $"{canvas}");
  305. }
  306. [Fact, SetupFakeDriver]
  307. public void Zero_Length_Intersections ()
  308. {
  309. // Draw at 1,2 within client area of View (i.e. leave a top and left margin of 1)
  310. // This proves we aren't drawing excess above
  311. int x = 1;
  312. int y = 2;
  313. int width = 5;
  314. int height = 2;
  315. var lc = new LineCanvas ();
  316. // ╔╡╞═════╗
  317. // Add a short horiz line for ╔╡
  318. lc.AddLine (new Point (x, y), 2, Orientation.Horizontal, LineStyle.Double);
  319. //LHS line down
  320. lc.AddLine (new Point (x, y), height, Orientation.Vertical, LineStyle.Double);
  321. //Vertical line before Title, results in a ╡
  322. lc.AddLine (new Point (x + 1, y), 0, Orientation.Vertical, LineStyle.Single);
  323. //Vertical line after Title, results in a ╞
  324. lc.AddLine (new Point (x + 2, y), 0, Orientation.Vertical, LineStyle.Single);
  325. // remainder of top line
  326. lc.AddLine (new Point (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double);
  327. //RHS line down
  328. lc.AddLine (new Point (x + width, y), height, Orientation.Vertical, LineStyle.Double);
  329. string looksLike = @"
  330. ╔╡╞══╗
  331. ║ ║";
  332. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{lc}");
  333. }
  334. [InlineData (LineStyle.Single)]
  335. [InlineData (LineStyle.Rounded)]
  336. [Theory, AutoInitShutdown]
  337. public void View_Draws_Horizontal (LineStyle style)
  338. {
  339. var v = GetCanvas (out var canvas);
  340. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, style);
  341. v.Draw ();
  342. string looksLike =
  343. @"
  344. ──";
  345. TestHelpers.AssertDriverContentsAre (looksLike, output);
  346. }
  347. [Fact, AutoInitShutdown]
  348. public void View_Draws_Horizontal_Double ()
  349. {
  350. var v = GetCanvas (out var canvas);
  351. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Double);
  352. v.Draw ();
  353. string looksLike =
  354. @"
  355. ══";
  356. TestHelpers.AssertDriverContentsAre (looksLike, output);
  357. }
  358. [InlineData (LineStyle.Single)]
  359. [InlineData (LineStyle.Rounded)]
  360. [Theory, AutoInitShutdown]
  361. public void View_Draws_Vertical (LineStyle style)
  362. {
  363. var v = GetCanvas (out var canvas);
  364. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, style);
  365. v.Draw ();
  366. string looksLike =
  367. @"
  368. │";
  369. TestHelpers.AssertDriverContentsAre (looksLike, output);
  370. }
  371. [Fact, AutoInitShutdown]
  372. public void View_Draws_Vertical_Double ()
  373. {
  374. var v = GetCanvas (out var canvas);
  375. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Double);
  376. v.Draw ();
  377. string looksLike =
  378. @"
  379. ║";
  380. TestHelpers.AssertDriverContentsAre (looksLike, output);
  381. }
  382. /// <summary>
  383. /// This test demonstrates that corners are only drawn when lines overlap.
  384. /// Not when they terminate adjacent to one another.
  385. /// </summary>
  386. [Fact, AutoInitShutdown]
  387. public void View_Draws_Corner_NoOverlap ()
  388. {
  389. var v = GetCanvas (out var canvas);
  390. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  391. canvas.AddLine (new Point (0, 1), 2, Orientation.Vertical, LineStyle.Single);
  392. v.Draw ();
  393. string looksLike =
  394. @"
  395. ──
  396. │";
  397. TestHelpers.AssertDriverContentsAre (looksLike, output);
  398. }
  399. /// <summary>
  400. /// This test demonstrates how to correctly trigger a corner. By
  401. /// overlapping the lines in the same cell
  402. /// </summary>
  403. [Fact, AutoInitShutdown]
  404. public void View_Draws_Corner_Correct ()
  405. {
  406. var v = GetCanvas (out var canvas);
  407. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  408. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Single);
  409. v.Draw ();
  410. string looksLike =
  411. @"
  412. ┌─
  413. │";
  414. TestHelpers.AssertDriverContentsAre (looksLike, output);
  415. }
  416. [Fact, SetupFakeDriver]
  417. public void Top_With_1Down ()
  418. {
  419. var canvas = new LineCanvas ();
  420. // Top ─
  421. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, LineStyle.Single);
  422. // Bottom ─
  423. canvas.AddLine (new Point (1, 1), -1, Orientation.Horizontal, LineStyle.Single);
  424. //// Right down
  425. //canvas.AddLine (new Point (9, 0), 3, Orientation.Vertical, LineStyle.Single);
  426. //// Bottom
  427. //canvas.AddLine (new Point (9, 3), -10, Orientation.Horizontal, LineStyle.Single);
  428. //// Left Up
  429. //canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, LineStyle.Single);
  430. Assert.Equal (new Rect (0, 0, 2, 2), canvas.Bounds);
  431. var map = canvas.GetMap ();
  432. Assert.Equal (2, map.Count);
  433. TestHelpers.AssertEqual (output, @"
  434. ─",
  435. $"{Environment.NewLine}{canvas}");
  436. }
  437. [Fact, SetupFakeDriver]
  438. public void Window ()
  439. {
  440. var canvas = new LineCanvas ();
  441. // Frame
  442. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Single);
  443. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
  444. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Single);
  445. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Single);
  446. // Cross
  447. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Single);
  448. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Single);
  449. string looksLike =
  450. @"
  451. ┌────┬───┐
  452. │ │ │
  453. ├────┼───┤
  454. │ │ │
  455. └────┴───┘";
  456. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  457. }
  458. /// <summary>
  459. /// Demonstrates when <see cref="LineStyle.Rounded"/> corners are used. Notice how
  460. /// not all lines declare rounded. If there are 1+ lines intersecting and a corner is
  461. /// to be used then if any of them are rounded a rounded corner is used.
  462. /// </summary>
  463. [Fact, AutoInitShutdown]
  464. public void View_Draws_Window_Rounded ()
  465. {
  466. var v = GetCanvas (out var canvas);
  467. // outer box
  468. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Rounded);
  469. // LineStyle.Single is ignored because corner overlaps with the above line which is Rounded
  470. // this results in a rounded corner being used.
  471. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
  472. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded);
  473. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Single);
  474. // These lines say rounded but they will result in the T sections which are never rounded.
  475. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Rounded);
  476. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Rounded);
  477. v.Draw ();
  478. string looksLike =
  479. @"
  480. ╭────┬───╮
  481. │ │ │
  482. ├────┼───┤
  483. │ │ │
  484. ╰────┴───╯";
  485. TestHelpers.AssertDriverContentsAre (looksLike, output);
  486. }
  487. [Fact, AutoInitShutdown]
  488. public void View_Draws_Window_Double ()
  489. {
  490. var v = GetCanvas (out var canvas);
  491. // outer box
  492. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Double);
  493. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Double);
  494. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Double);
  495. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Double);
  496. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Double);
  497. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Double);
  498. v.Draw ();
  499. string looksLike =
  500. @"
  501. ╔════╦═══╗
  502. ║ ║ ║
  503. ╠════╬═══╣
  504. ║ ║ ║
  505. ╚════╩═══╝";
  506. TestHelpers.AssertDriverContentsAre (looksLike, output);
  507. }
  508. [Theory, AutoInitShutdown]
  509. [InlineData (LineStyle.Single)]
  510. [InlineData (LineStyle.Rounded)]
  511. public void View_Draws_Window_DoubleTop_SingleSides (LineStyle thinStyle)
  512. {
  513. var v = GetCanvas (out var canvas);
  514. // outer box
  515. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Double);
  516. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, thinStyle);
  517. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Double);
  518. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, thinStyle);
  519. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, thinStyle);
  520. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Double);
  521. v.Draw ();
  522. string looksLike =
  523. @"
  524. ╒════╤═══╕
  525. │ │ │
  526. ╞════╪═══╡
  527. │ │ │
  528. ╘════╧═══╛
  529. ";
  530. TestHelpers.AssertDriverContentsAre (looksLike, output);
  531. }
  532. [Theory, AutoInitShutdown]
  533. [InlineData (LineStyle.Single)]
  534. [InlineData (LineStyle.Rounded)]
  535. public void View_Draws_Window_SingleTop_DoubleSides (LineStyle thinStyle)
  536. {
  537. var v = GetCanvas (out var canvas);
  538. // outer box
  539. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, thinStyle);
  540. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Double);
  541. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, thinStyle);
  542. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Double);
  543. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Double);
  544. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, thinStyle);
  545. v.Draw ();
  546. string looksLike =
  547. @"
  548. ╓────╥───╖
  549. ║ ║ ║
  550. ╟────╫───╢
  551. ║ ║ ║
  552. ╙────╨───╜
  553. ";
  554. TestHelpers.AssertDriverContentsAre (looksLike, output);
  555. }
  556. [Fact, AutoInitShutdown]
  557. public void TestLineCanvas_Window_Heavy ()
  558. {
  559. var v = GetCanvas (out var canvas);
  560. // outer box
  561. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
  562. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  563. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
  564. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
  565. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  566. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
  567. v.Draw ();
  568. string looksLike =
  569. @"
  570. ┏━━━━┳━━━┓
  571. ┃ ┃ ┃
  572. ┣━━━━╋━━━┫
  573. ┃ ┃ ┃
  574. ┗━━━━┻━━━┛";
  575. TestHelpers.AssertDriverContentsAre (looksLike, output);
  576. }
  577. [Theory, AutoInitShutdown]
  578. [InlineData (LineStyle.Single)]
  579. [InlineData (LineStyle.Rounded)]
  580. public void TestLineCanvas_Window_HeavyTop_ThinSides (LineStyle thinStyle)
  581. {
  582. var v = GetCanvas (out var canvas);
  583. // outer box
  584. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
  585. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, thinStyle);
  586. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
  587. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, thinStyle);
  588. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, thinStyle);
  589. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
  590. v.Draw ();
  591. string looksLike =
  592. @"
  593. ┍━━━━┯━━━┑
  594. │ │ │
  595. ┝━━━━┿━━━┥
  596. │ │ │
  597. ┕━━━━┷━━━┙
  598. ";
  599. TestHelpers.AssertDriverContentsAre (looksLike, output);
  600. }
  601. [Theory, AutoInitShutdown]
  602. [InlineData (LineStyle.Single)]
  603. [InlineData (LineStyle.Rounded)]
  604. public void TestLineCanvas_Window_ThinTop_HeavySides (LineStyle thinStyle)
  605. {
  606. var v = GetCanvas (out var canvas);
  607. // outer box
  608. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, thinStyle);
  609. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  610. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, thinStyle);
  611. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
  612. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  613. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, thinStyle);
  614. v.Draw ();
  615. string looksLike =
  616. @"
  617. ┎────┰───┒
  618. ┃ ┃ ┃
  619. ┠────╂───┨
  620. ┃ ┃ ┃
  621. ┖────┸───┚
  622. ";
  623. TestHelpers.AssertDriverContentsAre (looksLike, output);
  624. }
  625. [Fact, AutoInitShutdown]
  626. public void TestLineCanvas_LeaveMargin_Top1_Left1 ()
  627. {
  628. var canvas = new LineCanvas ();
  629. // Upper box
  630. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  631. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Single);
  632. string looksLike =
  633. @"
  634. ┌─
  635. │ ";
  636. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  637. }
  638. [Fact, SetupFakeDriver]
  639. public void Top_Left_From_TopRight_LeftUp ()
  640. {
  641. var canvas = new LineCanvas ();
  642. // Upper box
  643. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  644. canvas.AddLine (new Point (0, 1), -2, Orientation.Vertical, LineStyle.Single);
  645. string looksLike =
  646. @"
  647. ┌─
  648. │ ";
  649. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  650. }
  651. // [Fact, SetupFakeDriver]
  652. // public void LeaveMargin_Top1_Left1 ()
  653. // {
  654. // var canvas = new LineCanvas ();
  655. // // Upper box
  656. // canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, LineStyle.Single);
  657. // canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, LineStyle.Single);
  658. // canvas.AddLine (new Point (8, 3), -9, Orientation.Horizontal, LineStyle.Single);
  659. // canvas.AddLine (new Point (0, 2), -3, Orientation.Vertical, LineStyle.Single);
  660. // // Lower Box
  661. // canvas.AddLine (new Point (5, 0), 2, Orientation.Vertical, LineStyle.Single);
  662. // canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, LineStyle.Single);
  663. // string looksLike =
  664. //@"
  665. //┌────┬──┐
  666. //│ │ │
  667. //├────┼──┤
  668. //└────┴──┘
  669. //";
  670. // Assert.Equal (looksLike, $"{Environment.NewLine}{canvas}");
  671. // }
  672. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, "═")]
  673. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, "║")]
  674. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, "─")]
  675. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, "│")]
  676. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, "═")]
  677. [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Double, "║")]
  678. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, "─")]
  679. [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Single, "│")]
  680. [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Double, "══")]
  681. [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Double, "║\n║")]
  682. [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Single, "──")]
  683. [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Single, "│\n│")]
  684. [AutoInitShutdown, Theory]
  685. public void View_Draws_1LineTests (
  686. int x1, int y1, int length, Orientation o1, LineStyle s1,
  687. string expected
  688. )
  689. {
  690. var v = GetCanvas (out var lc);
  691. v.Width = 10;
  692. v.Height = 10;
  693. v.Bounds = new Rect (0, 0, 10, 10);
  694. lc.AddLine (new Point (x1, y1), length, o1, s1);
  695. v.Draw ();
  696. TestHelpers.AssertDriverContentsAre (expected, output);
  697. }
  698. [Theory, AutoInitShutdown]
  699. // Horizontal lines with a vertical zero-length
  700. [InlineData (
  701. 0, 0, 1, Orientation.Horizontal, LineStyle.Double,
  702. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "╞"
  703. )]
  704. [InlineData (
  705. 0, 0, -1, Orientation.Horizontal, LineStyle.Double,
  706. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "╡"
  707. )]
  708. [InlineData (
  709. 0, 0, 1, Orientation.Horizontal, LineStyle.Single,
  710. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╟"
  711. )]
  712. [InlineData (
  713. 0, 0, -1, Orientation.Horizontal, LineStyle.Single,
  714. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╢"
  715. )]
  716. [InlineData (
  717. 0, 0, 1, Orientation.Horizontal, LineStyle.Single,
  718. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "├"
  719. )]
  720. [InlineData (
  721. 0, 0, -1, Orientation.Horizontal, LineStyle.Single,
  722. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "┤"
  723. )]
  724. [InlineData (
  725. 0, 0, 1, Orientation.Horizontal, LineStyle.Double,
  726. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╠"
  727. )]
  728. [InlineData (
  729. 0, 0, -1, Orientation.Horizontal, LineStyle.Double,
  730. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╣"
  731. )]
  732. // Vertical lines with a horizontal zero-length
  733. [InlineData (
  734. 0, 0, 1, Orientation.Vertical, LineStyle.Double,
  735. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╥"
  736. )]
  737. [InlineData (
  738. 0, 0, -1, Orientation.Vertical, LineStyle.Double,
  739. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╨"
  740. )]
  741. [InlineData (
  742. 0, 0, 1, Orientation.Vertical, LineStyle.Single,
  743. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╤"
  744. )]
  745. [InlineData (
  746. 0, 0, -1, Orientation.Vertical, LineStyle.Single,
  747. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╧"
  748. )]
  749. [InlineData (
  750. 0, 0, 1, Orientation.Vertical, LineStyle.Single,
  751. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┬"
  752. )]
  753. [InlineData (
  754. 0, 0, -1, Orientation.Vertical, LineStyle.Single,
  755. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┴"
  756. )]
  757. [InlineData (
  758. 0, 0, 1, Orientation.Vertical, LineStyle.Double,
  759. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╦"
  760. )]
  761. [InlineData (
  762. 0, 0, -1, Orientation.Vertical, LineStyle.Double,
  763. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╩"
  764. )]
  765. // Crosses (two zero-length)
  766. [InlineData (
  767. 0, 0, 0, Orientation.Vertical, LineStyle.Double,
  768. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╫"
  769. )]
  770. [InlineData (
  771. 0, 0, 0, Orientation.Vertical, LineStyle.Single,
  772. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╪"
  773. )]
  774. [InlineData (
  775. 0, 0, 0, Orientation.Vertical, LineStyle.Single,
  776. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┼"
  777. )]
  778. [InlineData (
  779. 0, 0, 0, Orientation.Vertical, LineStyle.Double,
  780. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╬"
  781. )]
  782. public void Add_2_Lines (
  783. int x1, int y1, int len1, Orientation o1, LineStyle s1,
  784. int x2, int y2, int len2, Orientation o2, LineStyle s2,
  785. string expected
  786. )
  787. {
  788. var v = GetCanvas (out var lc);
  789. v.Width = 10;
  790. v.Height = 10;
  791. v.Bounds = new Rect (0, 0, 10, 10);
  792. lc.AddLine (new Point (x1, y1), len1, o1, s1);
  793. lc.AddLine (new Point (x2, y2), len2, o2, s2);
  794. TestHelpers.AssertEqual (output, expected, lc.ToString ());
  795. }
  796. // TODO: Remove this and make all LineCanvas tests independent of View
  797. /// <summary>
  798. /// Creates a new <see cref="View"/> into which a <see cref="LineCanvas"/> is rendered
  799. /// at <see cref="View.DrawContentComplete"/> time.
  800. /// </summary>
  801. /// <param name="canvas">The <see cref="LineCanvas"/> you can draw into.</param>
  802. /// <param name="offsetX">How far to offset drawing in X</param>
  803. /// <param name="offsetY">How far to offset drawing in Y</param>
  804. /// <returns></returns>
  805. private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0)
  806. {
  807. var v = new View {
  808. Width = 10,
  809. Height = 5,
  810. Bounds = new Rect (0, 0, 10, 5)
  811. };
  812. Application.Top.Add (v);
  813. Application.Begin (Application.Top);
  814. var canvasCopy = canvas = new LineCanvas ();
  815. v.DrawContentComplete += (s, e) => {
  816. v.Clear ();
  817. foreach (var p in canvasCopy.GetMap ()) {
  818. v.AddRune (
  819. offsetX + p.Key.X,
  820. offsetY + p.Key.Y,
  821. p.Value);
  822. }
  823. canvasCopy.Clear ();
  824. };
  825. return v;
  826. }
  827. }
  828. }