LineCanvasTests.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  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 (0, 0, Orientation.Horizontal, "─")]
  186. [InlineData (1, 0, Orientation.Horizontal, "─")]
  187. [InlineData (0, 1, Orientation.Horizontal, "─")]
  188. [InlineData (0, 0, Orientation.Vertical, "│")]
  189. [InlineData (1, 0, Orientation.Vertical, "│")]
  190. [InlineData (0, 1, Orientation.Vertical, "│")]
  191. [Theory, SetupFakeDriver]
  192. public void Length_Zero_Alone_Is_Line (int x, int y, Orientation orientation, string expected)
  193. {
  194. var lc = new LineCanvas ();
  195. // Add a line at 0, 0 that's has length of 0
  196. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  197. TestHelpers.AssertEqual (output, expected, $"{lc}");
  198. }
  199. [InlineData (0, 0, Orientation.Horizontal, "┼")]
  200. [InlineData (1, 0, Orientation.Horizontal, "┼")]
  201. [InlineData (0, 1, Orientation.Horizontal, "┼")]
  202. [InlineData (0, 0, Orientation.Vertical, "┼")]
  203. [InlineData (1, 0, Orientation.Vertical, "┼")]
  204. [InlineData (0, 1, Orientation.Vertical, "┼")]
  205. [Theory, SetupFakeDriver]
  206. public void Length_Zero_Cross_Is_Cross (int x, int y, Orientation orientation, string expected)
  207. {
  208. var lc = new LineCanvas ();
  209. // Add point at opposite orientation
  210. lc.AddLine (new Point (0, 0), 0, orientation == Orientation.Horizontal ? Orientation.Vertical : Orientation.Horizontal, LineStyle.Single);
  211. // Add a line at 0, 0 that's has length of 0
  212. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  213. TestHelpers.AssertEqual (output, expected, $"{lc}");
  214. }
  215. [InlineData (0, 0, Orientation.Horizontal, "╥")]
  216. [InlineData (1, 0, Orientation.Horizontal, "╥")]
  217. [InlineData (0, 1, Orientation.Horizontal, "╥")]
  218. [InlineData (0, 0, Orientation.Vertical, "╞")]
  219. [InlineData (1, 0, Orientation.Vertical, "╞")]
  220. [InlineData (0, 1, Orientation.Vertical, "╞")]
  221. [Theory, SetupFakeDriver]
  222. public void Length_Zero_NextTo_Opposite_Is_T (int x, int y, Orientation orientation, string expected)
  223. {
  224. var lc = new LineCanvas ();
  225. // Add line with length of 1 in opposite orientation starting at same location
  226. if (orientation == Orientation.Horizontal) {
  227. lc.AddLine (new Point (0, 0), 1, Orientation.Vertical, LineStyle.Double);
  228. } else {
  229. lc.AddLine (new Point (0, 0), 1, Orientation.Horizontal, LineStyle.Double);
  230. }
  231. // Add a line at 0, 0 that's has length of 0
  232. lc.AddLine (new Point (0, 0), 0, orientation, LineStyle.Single);
  233. TestHelpers.AssertEqual (output, expected, $"{lc}");
  234. }
  235. [InlineData (0, 0, Orientation.Horizontal, "─")]
  236. [InlineData (1, 0, Orientation.Horizontal, "─")]
  237. [InlineData (0, 1, Orientation.Horizontal, "─")]
  238. [InlineData (-1, 0, Orientation.Horizontal, "─")]
  239. [InlineData (0, -1, Orientation.Horizontal, "─")]
  240. [InlineData (-1, -1, Orientation.Horizontal, "─")]
  241. [InlineData (0, 0, Orientation.Vertical, "│")]
  242. [InlineData (1, 0, Orientation.Vertical, "│")]
  243. [InlineData (0, 1, Orientation.Vertical, "│")]
  244. [InlineData (0, -1, Orientation.Vertical, "│")]
  245. [InlineData (-1, 0, Orientation.Vertical, "│")]
  246. [InlineData (-1, -1, Orientation.Vertical, "│")]
  247. [Theory, SetupFakeDriver]
  248. public void Length_0_Is_1_Long (int x, int y, Orientation orientation, string expected)
  249. {
  250. var canvas = new LineCanvas ();
  251. // Add a line at 5, 5 that's has length of 1
  252. canvas.AddLine (new Point (x, y), 1, orientation, LineStyle.Single);
  253. TestHelpers.AssertEqual (output, $"{expected}", $"{canvas}");
  254. }
  255. // X is offset by 2
  256. [InlineData (0, 0, 1, Orientation.Horizontal, "─")]
  257. [InlineData (1, 0, 1, Orientation.Horizontal, "─")]
  258. [InlineData (0, 1, 1, Orientation.Horizontal, "─")]
  259. [InlineData (0, 0, 1, Orientation.Vertical, "│")]
  260. [InlineData (1, 0, 1, Orientation.Vertical, "│")]
  261. [InlineData (0, 1, 1, Orientation.Vertical, "│")]
  262. [InlineData (-1, 0, 1, Orientation.Horizontal, "─")]
  263. [InlineData (0, -1, 1, Orientation.Horizontal, "─")]
  264. [InlineData (-1, 0, 1, Orientation.Vertical, "│")]
  265. [InlineData (0, -1, 1, Orientation.Vertical, "│")]
  266. [InlineData (0, 0, -1, Orientation.Horizontal, "─")]
  267. [InlineData (1, 0, -1, Orientation.Horizontal, "─")]
  268. [InlineData (0, 1, -1, Orientation.Horizontal, "─")]
  269. [InlineData (0, 0, -1, Orientation.Vertical, "│")]
  270. [InlineData (1, 0, -1, Orientation.Vertical, "│")]
  271. [InlineData (0, 1, -1, Orientation.Vertical, "│")]
  272. [InlineData (-1, 0, -1, Orientation.Horizontal, "─")]
  273. [InlineData (0, -1, -1, Orientation.Horizontal, "─")]
  274. [InlineData (-1, 0, -1, Orientation.Vertical, "│")]
  275. [InlineData (0, -1, -1, Orientation.Vertical, "│")]
  276. [InlineData (0, 0, 2, Orientation.Horizontal, "──")]
  277. [InlineData (1, 0, 2, Orientation.Horizontal, "──")]
  278. [InlineData (0, 1, 2, Orientation.Horizontal, "──")]
  279. [InlineData (1, 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. [InlineData (0, 0, -2, Orientation.Horizontal, "──")]
  290. [InlineData (1, 0, -2, Orientation.Horizontal, "──")]
  291. [InlineData (0, 1, -2, Orientation.Horizontal, "──")]
  292. [InlineData (0, 0, -2, Orientation.Vertical, "│\r\n│")]
  293. [InlineData (1, 0, -2, Orientation.Vertical, "│\r\n│")]
  294. [InlineData (0, 1, -2, Orientation.Vertical, "│\r\n│")]
  295. [InlineData (1, 1, -2, Orientation.Vertical, "│\r\n│")]
  296. [InlineData (-1, 0, -2, Orientation.Horizontal, "──")]
  297. [InlineData (0, -1, -2, Orientation.Horizontal, "──")]
  298. [InlineData (-1, 0, -2, Orientation.Vertical, "│\r\n│")]
  299. [InlineData (0, -1, -2, Orientation.Vertical, "│\r\n│")]
  300. [InlineData (-1, -1, -2, Orientation.Vertical, "│\r\n│")]
  301. [Theory, SetupFakeDriver]
  302. public void Length_n_Is_n_Long (int x, int y, int length, Orientation orientation, string expected)
  303. {
  304. var canvas = new LineCanvas ();
  305. canvas.AddLine (new Point (x, y), length, orientation, LineStyle.Single);
  306. var result = canvas.ToString ();
  307. TestHelpers.AssertEqual (output, expected, result);
  308. }
  309. [Fact, SetupFakeDriver]
  310. public void Length_Negative ()
  311. {
  312. var offset = new Point (5, 5);
  313. var canvas = new LineCanvas ();
  314. canvas.AddLine (offset, -3, Orientation.Horizontal, LineStyle.Single);
  315. string looksLike = "───";
  316. Assert.Equal (looksLike, $"{canvas}");
  317. }
  318. [Fact, SetupFakeDriver]
  319. public void Zero_Length_Intersections ()
  320. {
  321. // Draw at 1,2 within client area of View (i.e. leave a top and left margin of 1)
  322. // This proves we aren't drawing excess above
  323. int x = 1;
  324. int y = 2;
  325. int width = 5;
  326. int height = 2;
  327. var lc = new LineCanvas ();
  328. // ╔╡╞═════╗
  329. // Add a short horiz line for ╔╡
  330. lc.AddLine (new Point (x, y), 2, Orientation.Horizontal, LineStyle.Double);
  331. //LHS line down
  332. lc.AddLine (new Point (x, y), height, Orientation.Vertical, LineStyle.Double);
  333. //Vertical line before Title, results in a ╡
  334. lc.AddLine (new Point (x + 1, y), 0, Orientation.Vertical, LineStyle.Single);
  335. //Vertical line after Title, results in a ╞
  336. lc.AddLine (new Point (x + 2, y), 0, Orientation.Vertical, LineStyle.Single);
  337. // remainder of top line
  338. lc.AddLine (new Point (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double);
  339. //RHS line down
  340. lc.AddLine (new Point (x + width, y), height, Orientation.Vertical, LineStyle.Double);
  341. string looksLike = @"
  342. ╔╡╞══╗
  343. ║ ║";
  344. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{lc}");
  345. }
  346. [InlineData (LineStyle.Single)]
  347. [InlineData (LineStyle.Rounded)]
  348. [Theory, AutoInitShutdown]
  349. public void View_Draws_Horizontal (LineStyle style)
  350. {
  351. var v = GetCanvas (out var canvas);
  352. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, style);
  353. v.Draw ();
  354. string looksLike =
  355. @"
  356. ──";
  357. TestHelpers.AssertDriverContentsAre (looksLike, output);
  358. }
  359. [Fact, AutoInitShutdown]
  360. public void View_Draws_Horizontal_Double ()
  361. {
  362. var v = GetCanvas (out var canvas);
  363. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Double);
  364. v.Draw ();
  365. string looksLike =
  366. @"
  367. ══";
  368. TestHelpers.AssertDriverContentsAre (looksLike, output);
  369. }
  370. [InlineData (LineStyle.Single)]
  371. [InlineData (LineStyle.Rounded)]
  372. [Theory, AutoInitShutdown]
  373. public void View_Draws_Vertical (LineStyle style)
  374. {
  375. var v = GetCanvas (out var canvas);
  376. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, style);
  377. v.Draw ();
  378. string looksLike =
  379. @"
  380. │";
  381. TestHelpers.AssertDriverContentsAre (looksLike, output);
  382. }
  383. [Fact, AutoInitShutdown]
  384. public void View_Draws_Vertical_Double ()
  385. {
  386. var v = GetCanvas (out var canvas);
  387. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Double);
  388. v.Draw ();
  389. string looksLike =
  390. @"
  391. ║";
  392. TestHelpers.AssertDriverContentsAre (looksLike, output);
  393. }
  394. /// <summary>
  395. /// This test demonstrates that corners are only drawn when lines overlap.
  396. /// Not when they terminate adjacent to one another.
  397. /// </summary>
  398. [Fact, AutoInitShutdown]
  399. public void View_Draws_Corner_NoOverlap ()
  400. {
  401. var v = GetCanvas (out var canvas);
  402. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  403. canvas.AddLine (new Point (0, 1), 2, Orientation.Vertical, LineStyle.Single);
  404. v.Draw ();
  405. string looksLike =
  406. @"
  407. ──
  408. │";
  409. TestHelpers.AssertDriverContentsAre (looksLike, output);
  410. }
  411. /// <summary>
  412. /// This test demonstrates how to correctly trigger a corner. By
  413. /// overlapping the lines in the same cell
  414. /// </summary>
  415. [Fact, AutoInitShutdown]
  416. public void View_Draws_Corner_Correct ()
  417. {
  418. var v = GetCanvas (out var canvas);
  419. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  420. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Single);
  421. v.Draw ();
  422. string looksLike =
  423. @"
  424. ┌─
  425. │";
  426. TestHelpers.AssertDriverContentsAre (looksLike, output);
  427. }
  428. [Fact, SetupFakeDriver]
  429. public void Top_With_1Down ()
  430. {
  431. var canvas = new LineCanvas ();
  432. // Top ─
  433. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, LineStyle.Single);
  434. // Bottom ─
  435. canvas.AddLine (new Point (1, 1), -1, Orientation.Horizontal, LineStyle.Single);
  436. //// Right down
  437. //canvas.AddLine (new Point (9, 0), 3, Orientation.Vertical, LineStyle.Single);
  438. //// Bottom
  439. //canvas.AddLine (new Point (9, 3), -10, Orientation.Horizontal, LineStyle.Single);
  440. //// Left Up
  441. //canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, LineStyle.Single);
  442. Assert.Equal (new Rect (0, 0, 2, 2), canvas.Bounds);
  443. var map = canvas.GetMap ();
  444. Assert.Equal (2, map.Count);
  445. TestHelpers.AssertEqual (output, @"
  446. ─",
  447. $"{Environment.NewLine}{canvas}");
  448. }
  449. [Fact, SetupFakeDriver]
  450. public void Window ()
  451. {
  452. var canvas = new LineCanvas ();
  453. // Frame
  454. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Single);
  455. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
  456. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Single);
  457. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Single);
  458. // Cross
  459. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Single);
  460. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Single);
  461. string looksLike =
  462. @"
  463. ┌────┬───┐
  464. │ │ │
  465. ├────┼───┤
  466. │ │ │
  467. └────┴───┘";
  468. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  469. }
  470. /// <summary>
  471. /// Demonstrates when <see cref="LineStyle.Rounded"/> corners are used. Notice how
  472. /// not all lines declare rounded. If there are 1+ lines intersecting and a corner is
  473. /// to be used then if any of them are rounded a rounded corner is used.
  474. /// </summary>
  475. [Fact, AutoInitShutdown]
  476. public void View_Draws_Window_Rounded ()
  477. {
  478. var v = GetCanvas (out var canvas);
  479. // outer box
  480. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Rounded);
  481. // LineStyle.Single is ignored because corner overlaps with the above line which is Rounded
  482. // this results in a rounded corner being used.
  483. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
  484. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded);
  485. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Single);
  486. // These lines say rounded but they will result in the T sections which are never rounded.
  487. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Rounded);
  488. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Rounded);
  489. v.Draw ();
  490. string looksLike =
  491. @"
  492. ╭────┬───╮
  493. │ │ │
  494. ├────┼───┤
  495. │ │ │
  496. ╰────┴───╯";
  497. TestHelpers.AssertDriverContentsAre (looksLike, output);
  498. }
  499. [Fact, AutoInitShutdown]
  500. public void View_Draws_Window_Double ()
  501. {
  502. var v = GetCanvas (out var canvas);
  503. // outer box
  504. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Double);
  505. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Double);
  506. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Double);
  507. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Double);
  508. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Double);
  509. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Double);
  510. v.Draw ();
  511. string looksLike =
  512. @"
  513. ╔════╦═══╗
  514. ║ ║ ║
  515. ╠════╬═══╣
  516. ║ ║ ║
  517. ╚════╩═══╝";
  518. TestHelpers.AssertDriverContentsAre (looksLike, output);
  519. }
  520. [Theory, AutoInitShutdown]
  521. [InlineData (LineStyle.Single)]
  522. [InlineData (LineStyle.Rounded)]
  523. public void View_Draws_Window_DoubleTop_SingleSides (LineStyle thinStyle)
  524. {
  525. var v = GetCanvas (out var canvas);
  526. // outer box
  527. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Double);
  528. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, thinStyle);
  529. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Double);
  530. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, thinStyle);
  531. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, thinStyle);
  532. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Double);
  533. v.Draw ();
  534. string looksLike =
  535. @"
  536. ╒════╤═══╕
  537. │ │ │
  538. ╞════╪═══╡
  539. │ │ │
  540. ╘════╧═══╛
  541. ";
  542. TestHelpers.AssertDriverContentsAre (looksLike, output);
  543. }
  544. [Theory, AutoInitShutdown]
  545. [InlineData (LineStyle.Single)]
  546. [InlineData (LineStyle.Rounded)]
  547. public void View_Draws_Window_SingleTop_DoubleSides (LineStyle thinStyle)
  548. {
  549. var v = GetCanvas (out var canvas);
  550. // outer box
  551. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, thinStyle);
  552. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Double);
  553. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, thinStyle);
  554. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Double);
  555. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Double);
  556. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, thinStyle);
  557. v.Draw ();
  558. string looksLike =
  559. @"
  560. ╓────╥───╖
  561. ║ ║ ║
  562. ╟────╫───╢
  563. ║ ║ ║
  564. ╙────╨───╜
  565. ";
  566. TestHelpers.AssertDriverContentsAre (looksLike, output);
  567. }
  568. [Fact, AutoInitShutdown]
  569. public void TestLineCanvas_Window_Heavy ()
  570. {
  571. var v = GetCanvas (out var canvas);
  572. // outer box
  573. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
  574. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  575. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
  576. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
  577. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  578. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
  579. v.Draw ();
  580. string looksLike =
  581. @"
  582. ┏━━━━┳━━━┓
  583. ┃ ┃ ┃
  584. ┣━━━━╋━━━┫
  585. ┃ ┃ ┃
  586. ┗━━━━┻━━━┛";
  587. TestHelpers.AssertDriverContentsAre (looksLike, output);
  588. }
  589. [Theory, AutoInitShutdown]
  590. [InlineData (LineStyle.Single)]
  591. [InlineData (LineStyle.Rounded)]
  592. public void TestLineCanvas_Window_HeavyTop_ThinSides (LineStyle thinStyle)
  593. {
  594. var v = GetCanvas (out var canvas);
  595. // outer box
  596. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
  597. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, thinStyle);
  598. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
  599. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, thinStyle);
  600. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, thinStyle);
  601. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
  602. v.Draw ();
  603. string looksLike =
  604. @"
  605. ┍━━━━┯━━━┑
  606. │ │ │
  607. ┝━━━━┿━━━┥
  608. │ │ │
  609. ┕━━━━┷━━━┙
  610. ";
  611. TestHelpers.AssertDriverContentsAre (looksLike, output);
  612. }
  613. [Theory, AutoInitShutdown]
  614. [InlineData (LineStyle.Single)]
  615. [InlineData (LineStyle.Rounded)]
  616. public void TestLineCanvas_Window_ThinTop_HeavySides (LineStyle thinStyle)
  617. {
  618. var v = GetCanvas (out var canvas);
  619. // outer box
  620. canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, thinStyle);
  621. canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  622. canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, thinStyle);
  623. canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
  624. canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
  625. canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, thinStyle);
  626. v.Draw ();
  627. string looksLike =
  628. @"
  629. ┎────┰───┒
  630. ┃ ┃ ┃
  631. ┠────╂───┨
  632. ┃ ┃ ┃
  633. ┖────┸───┚
  634. ";
  635. TestHelpers.AssertDriverContentsAre (looksLike, output);
  636. }
  637. [Fact, AutoInitShutdown]
  638. public void TestLineCanvas_LeaveMargin_Top1_Left1 ()
  639. {
  640. var canvas = new LineCanvas ();
  641. // Upper box
  642. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  643. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, LineStyle.Single);
  644. string looksLike =
  645. @"
  646. ┌─
  647. │ ";
  648. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  649. }
  650. [Fact, SetupFakeDriver]
  651. public void Top_Left_From_TopRight_LeftUp ()
  652. {
  653. var canvas = new LineCanvas ();
  654. // Upper box
  655. canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, LineStyle.Single);
  656. canvas.AddLine (new Point (0, 1), -2, Orientation.Vertical, LineStyle.Single);
  657. string looksLike =
  658. @"
  659. ┌─
  660. │ ";
  661. TestHelpers.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}");
  662. }
  663. // [Fact, SetupFakeDriver]
  664. // public void LeaveMargin_Top1_Left1 ()
  665. // {
  666. // var canvas = new LineCanvas ();
  667. // // Upper box
  668. // canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, LineStyle.Single);
  669. // canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, LineStyle.Single);
  670. // canvas.AddLine (new Point (8, 3), -9, Orientation.Horizontal, LineStyle.Single);
  671. // canvas.AddLine (new Point (0, 2), -3, Orientation.Vertical, LineStyle.Single);
  672. // // Lower Box
  673. // canvas.AddLine (new Point (5, 0), 2, Orientation.Vertical, LineStyle.Single);
  674. // canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, LineStyle.Single);
  675. // string looksLike =
  676. //@"
  677. //┌────┬──┐
  678. //│ │ │
  679. //├────┼──┤
  680. //└────┴──┘
  681. //";
  682. // Assert.Equal (looksLike, $"{Environment.NewLine}{canvas}");
  683. // }
  684. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, "═")]
  685. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, "║")]
  686. [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, "─")]
  687. [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, "│")]
  688. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, "═")]
  689. [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Double, "║")]
  690. [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, "─")]
  691. [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Single, "│")]
  692. [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Double, "══")]
  693. [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Double, "║\n║")]
  694. [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Single, "──")]
  695. [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Single, "│\n│")]
  696. [AutoInitShutdown, Theory]
  697. public void View_Draws_1LineTests (
  698. int x1, int y1, int length, Orientation o1, LineStyle s1,
  699. string expected
  700. )
  701. {
  702. var v = GetCanvas (out var lc);
  703. v.Width = 10;
  704. v.Height = 10;
  705. v.Bounds = new Rect (0, 0, 10, 10);
  706. lc.AddLine (new Point (x1, y1), length, o1, s1);
  707. v.Draw ();
  708. TestHelpers.AssertDriverContentsAre (expected, output);
  709. }
  710. [Theory, AutoInitShutdown]
  711. // Horizontal lines with a vertical zero-length
  712. [InlineData (
  713. 0, 0, 1, Orientation.Horizontal, LineStyle.Double,
  714. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "╞"
  715. )]
  716. [InlineData (
  717. 0, 0, -1, Orientation.Horizontal, LineStyle.Double,
  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.Double, "╟"
  723. )]
  724. [InlineData (
  725. 0, 0, -1, Orientation.Horizontal, LineStyle.Single,
  726. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╢"
  727. )]
  728. [InlineData (
  729. 0, 0, 1, Orientation.Horizontal, LineStyle.Single,
  730. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "├"
  731. )]
  732. [InlineData (
  733. 0, 0, -1, Orientation.Horizontal, LineStyle.Single,
  734. 0, 0, 0, Orientation.Vertical, LineStyle.Single, "┤"
  735. )]
  736. [InlineData (
  737. 0, 0, 1, Orientation.Horizontal, LineStyle.Double,
  738. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╠"
  739. )]
  740. [InlineData (
  741. 0, 0, -1, Orientation.Horizontal, LineStyle.Double,
  742. 0, 0, 0, Orientation.Vertical, LineStyle.Double, "╣"
  743. )]
  744. // Vertical lines with a horizontal zero-length
  745. [InlineData (
  746. 0, 0, 1, Orientation.Vertical, LineStyle.Double,
  747. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╥"
  748. )]
  749. [InlineData (
  750. 0, 0, -1, Orientation.Vertical, LineStyle.Double,
  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.Double, "╤"
  756. )]
  757. [InlineData (
  758. 0, 0, -1, Orientation.Vertical, LineStyle.Single,
  759. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╧"
  760. )]
  761. [InlineData (
  762. 0, 0, 1, Orientation.Vertical, LineStyle.Single,
  763. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┬"
  764. )]
  765. [InlineData (
  766. 0, 0, -1, Orientation.Vertical, LineStyle.Single,
  767. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┴"
  768. )]
  769. [InlineData (
  770. 0, 0, 1, Orientation.Vertical, LineStyle.Double,
  771. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╦"
  772. )]
  773. [InlineData (
  774. 0, 0, -1, Orientation.Vertical, LineStyle.Double,
  775. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╩"
  776. )]
  777. // Crosses (two zero-length)
  778. [InlineData (
  779. 0, 0, 0, Orientation.Vertical, LineStyle.Double,
  780. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "╫"
  781. )]
  782. [InlineData (
  783. 0, 0, 0, Orientation.Vertical, LineStyle.Single,
  784. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╪"
  785. )]
  786. [InlineData (
  787. 0, 0, 0, Orientation.Vertical, LineStyle.Single,
  788. 0, 0, 0, Orientation.Horizontal, LineStyle.Single, "┼"
  789. )]
  790. [InlineData (
  791. 0, 0, 0, Orientation.Vertical, LineStyle.Double,
  792. 0, 0, 0, Orientation.Horizontal, LineStyle.Double, "╬"
  793. )]
  794. public void Add_2_Lines (
  795. int x1, int y1, int len1, Orientation o1, LineStyle s1,
  796. int x2, int y2, int len2, Orientation o2, LineStyle s2,
  797. string expected
  798. )
  799. {
  800. var v = GetCanvas (out var lc);
  801. v.Width = 10;
  802. v.Height = 10;
  803. v.Bounds = new Rect (0, 0, 10, 10);
  804. lc.AddLine (new Point (x1, y1), len1, o1, s1);
  805. lc.AddLine (new Point (x2, y2), len2, o2, s2);
  806. TestHelpers.AssertEqual (output, expected, lc.ToString ());
  807. }
  808. // TODO: Remove this and make all LineCanvas tests independent of View
  809. /// <summary>
  810. /// Creates a new <see cref="View"/> into which a <see cref="LineCanvas"/> is rendered
  811. /// at <see cref="View.DrawContentComplete"/> time.
  812. /// </summary>
  813. /// <param name="canvas">The <see cref="LineCanvas"/> you can draw into.</param>
  814. /// <param name="offsetX">How far to offset drawing in X</param>
  815. /// <param name="offsetY">How far to offset drawing in Y</param>
  816. /// <returns></returns>
  817. private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0)
  818. {
  819. var v = new View {
  820. Width = 10,
  821. Height = 5,
  822. Bounds = new Rect (0, 0, 10, 5)
  823. };
  824. Application.Top.Add (v);
  825. Application.Begin (Application.Top);
  826. var canvasCopy = canvas = new LineCanvas ();
  827. v.DrawContentComplete += (s, e) => {
  828. v.Clear ();
  829. foreach (var p in canvasCopy.GetMap ()) {
  830. v.AddRune (
  831. offsetX + p.Key.X,
  832. offsetY + p.Key.Y,
  833. p.Value);
  834. }
  835. canvasCopy.Clear ();
  836. };
  837. return v;
  838. }
  839. }
  840. }