LineCanvasTests.cs 33 KB

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