TreeTableSourceTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. using System.Text;
  2. using Xunit.Abstractions;
  3. namespace Terminal.Gui.ViewsTests;
  4. public class TreeTableSourceTests : IDisposable
  5. {
  6. private readonly Rune _origChecked;
  7. private readonly Rune _origUnchecked;
  8. private readonly ITestOutputHelper _output;
  9. public TreeTableSourceTests (ITestOutputHelper output)
  10. {
  11. _output = output;
  12. _origChecked = ConfigurationManager.Glyphs.CheckStateChecked;
  13. _origUnchecked = ConfigurationManager.Glyphs.CheckStateUnChecked;
  14. ConfigurationManager.Glyphs.CheckStateChecked = new Rune ('☑');
  15. ConfigurationManager.Glyphs.CheckStateUnChecked = new Rune ('☐');
  16. }
  17. public void Dispose ()
  18. {
  19. ConfigurationManager.Glyphs.CheckStateChecked = _origChecked;
  20. ConfigurationManager.Glyphs.CheckStateUnChecked = _origUnchecked;
  21. }
  22. [Fact]
  23. [SetupFakeDriver]
  24. public void TestTreeTableSource_BasicExpanding_WithKeyboard ()
  25. {
  26. ((FakeDriver)Application.Driver!).SetBufferSize (100, 100);
  27. TableView tv = GetTreeTable (out _);
  28. tv.Style.GetOrCreateColumnStyle (1).MinAcceptableWidth = 1;
  29. tv.Draw ();
  30. var expected =
  31. @"
  32. │Name │Description │
  33. ├──────────────┼───────────────────────┤
  34. │├+Lost Highway│Exciting night road │
  35. │└+Route 66 │Great race course │";
  36. TestHelpers.AssertDriverContentsAre (expected, _output);
  37. Assert.Equal (2, tv.Table.Rows);
  38. // top left is selected cell
  39. Assert.Equal (0, tv.SelectedRow);
  40. Assert.Equal (0, tv.SelectedColumn);
  41. // when pressing right we should expand the top route
  42. tv.NewKeyDownEvent (Key.CursorRight);
  43. View.SetClipToScreen ();
  44. tv.Draw ();
  45. expected =
  46. @"
  47. │Name │Description │
  48. ├─────────────────┼────────────────────┤
  49. │├-Lost Highway │Exciting night road │
  50. ││ ├─Ford Trans-Am│Talking thunderbird │
  51. ││ └─DeLorean │Time travelling car │
  52. │└+Route 66 │Great race course │
  53. ";
  54. TestHelpers.AssertDriverContentsAre (expected, _output);
  55. // when pressing left we should collapse the top route again
  56. tv.NewKeyDownEvent (Key.CursorLeft);
  57. View.SetClipToScreen ();
  58. tv.Draw ();
  59. expected =
  60. @"
  61. │Name │Description │
  62. ├──────────────┼───────────────────────┤
  63. │├+Lost Highway│Exciting night road │
  64. │└+Route 66 │Great race course │
  65. ";
  66. TestHelpers.AssertDriverContentsAre (expected, _output);
  67. }
  68. [Fact]
  69. [SetupFakeDriver]
  70. public void TestTreeTableSource_BasicExpanding_WithMouse ()
  71. {
  72. ((FakeDriver)Application.Driver!).SetBufferSize (100, 100);
  73. TableView tv = GetTreeTable (out _);
  74. tv.Style.GetOrCreateColumnStyle (1).MinAcceptableWidth = 1;
  75. View.SetClipToScreen ();
  76. tv.Draw ();
  77. var expected =
  78. @"
  79. │Name │Description │
  80. ├──────────────┼───────────────────────┤
  81. │├+Lost Highway│Exciting night road │
  82. │└+Route 66 │Great race course │";
  83. TestHelpers.AssertDriverContentsAre (expected, _output);
  84. Assert.Equal (2, tv.Table.Rows);
  85. // top left is selected cell
  86. Assert.Equal (0, tv.SelectedRow);
  87. Assert.Equal (0, tv.SelectedColumn);
  88. Assert.True (tv.NewMouseEvent (new MouseEventArgs { Position = new (2, 2), Flags = MouseFlags.Button1Clicked }));
  89. View.SetClipToScreen ();
  90. tv.Draw ();
  91. expected =
  92. @"
  93. │Name │Description │
  94. ├─────────────────┼────────────────────┤
  95. │├-Lost Highway │Exciting night road │
  96. ││ ├─Ford Trans-Am│Talking thunderbird │
  97. ││ └─DeLorean │Time travelling car │
  98. │└+Route 66 │Great race course │
  99. ";
  100. TestHelpers.AssertDriverContentsAre (expected, _output);
  101. // Clicking to the right/left of the expand/collapse does nothing
  102. tv.NewMouseEvent (new MouseEventArgs { Position = new (3, 2), Flags = MouseFlags.Button1Clicked });
  103. tv.Draw ();
  104. TestHelpers.AssertDriverContentsAre (expected, _output);
  105. tv.NewMouseEvent (new MouseEventArgs { Position = new (1, 2), Flags = MouseFlags.Button1Clicked });
  106. tv.Draw ();
  107. TestHelpers.AssertDriverContentsAre (expected, _output);
  108. // Clicking on the + again should collapse
  109. tv.NewMouseEvent (new MouseEventArgs { Position = new (2, 2), Flags = MouseFlags.Button1Clicked });
  110. View.SetClipToScreen ();
  111. tv.Draw ();
  112. expected =
  113. @"
  114. │Name │Description │
  115. ├──────────────┼───────────────────────┤
  116. │├+Lost Highway│Exciting night road │
  117. │└+Route 66 │Great race course │";
  118. TestHelpers.AssertDriverContentsAre (expected, _output);
  119. }
  120. [Fact]
  121. [AutoInitShutdown (configLocation:ConfigLocations.Default)]
  122. public void TestTreeTableSource_CombinedWithCheckboxes ()
  123. {
  124. Toplevel top = new ();
  125. TableView tv = GetTreeTable (out TreeView<IDescribedThing> treeSource);
  126. CheckBoxTableSourceWrapperByIndex checkSource;
  127. tv.Table = checkSource = new CheckBoxTableSourceWrapperByIndex (tv, tv.Table);
  128. tv.Style.GetOrCreateColumnStyle (2).MinAcceptableWidth = 1;
  129. top.Add (tv);
  130. Application.Begin (top);
  131. tv.Draw ();
  132. var expected =
  133. @"
  134. │ │Name │Description │
  135. ├─┼──────────────┼─────────────────────┤
  136. │☐│├+Lost Highway│Exciting night road │
  137. │☐│└+Route 66 │Great race course │
  138. ";
  139. TestHelpers.AssertDriverContentsAre (expected, _output);
  140. Assert.Equal (2, tv.Table.Rows);
  141. // top left is selected cell
  142. Assert.Equal (0, tv.SelectedRow);
  143. Assert.Equal (0, tv.SelectedColumn);
  144. // when pressing right we move to tree column
  145. tv.NewKeyDownEvent (Key.CursorRight);
  146. // now we are in tree column
  147. Assert.Equal (0, tv.SelectedRow);
  148. Assert.Equal (1, tv.SelectedColumn);
  149. Application.RaiseKeyDownEvent (Key.CursorRight);
  150. View.SetClipToScreen ();
  151. tv.Draw ();
  152. expected =
  153. @"
  154. │ │Name │Description │
  155. ├─┼─────────────────┼──────────────────┤
  156. │☐│├-Lost Highway │Exciting night roa│
  157. │☐││ ├─Ford Trans-Am│Talking thunderbir│
  158. │☐││ └─DeLorean │Time travelling ca│
  159. │☐│└+Route 66 │Great race course │
  160. ";
  161. TestHelpers.AssertDriverContentsAre (expected, _output);
  162. tv.NewKeyDownEvent (Key.CursorDown);
  163. tv.NewKeyDownEvent (Key.Space);
  164. View.SetClipToScreen ();
  165. tv.Draw ();
  166. expected =
  167. @"
  168. │ │Name │Description │
  169. ├─┼─────────────────┼──────────────────┤
  170. │☐│├-Lost Highway │Exciting night roa│
  171. │☑││ ├─Ford Trans-Am│Talking thunderbir│
  172. │☐││ └─DeLorean │Time travelling ca│
  173. │☐│└+Route 66 │Great race course │
  174. ";
  175. TestHelpers.AssertDriverContentsAre (expected, _output);
  176. IDescribedThing [] selectedObjects = checkSource.CheckedRows.Select (treeSource.GetObjectOnRow).ToArray ();
  177. IDescribedThing selected = Assert.Single (selectedObjects);
  178. Assert.Equal ("Ford Trans-Am", selected.Name);
  179. Assert.Equal ("Talking thunderbird car", selected.Description);
  180. top.Dispose ();
  181. }
  182. private TableView GetTreeTable (out TreeView<IDescribedThing> tree)
  183. {
  184. var tableView = new TableView ();
  185. tableView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
  186. tableView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
  187. tableView.Viewport = new Rectangle (0, 0, 40, 6);
  188. tableView.Style.ShowHorizontalHeaderUnderline = true;
  189. tableView.Style.ShowHorizontalHeaderOverline = false;
  190. tableView.Style.AlwaysShowHeaders = true;
  191. tableView.Style.SmoothHorizontalScrolling = true;
  192. tree = new TreeView<IDescribedThing> ();
  193. tree.AspectGetter = d => d.Name;
  194. tree.TreeBuilder = new DelegateTreeBuilder<IDescribedThing> (
  195. d => d is Road r
  196. ? r.Traffic
  197. : Enumerable.Empty<IDescribedThing> ()
  198. );
  199. tree.AddObject (
  200. new Road
  201. {
  202. Name = "Lost Highway",
  203. Description = "Exciting night road",
  204. Traffic = new List<Car>
  205. {
  206. new () { Name = "Ford Trans-Am", Description = "Talking thunderbird car" },
  207. new () { Name = "DeLorean", Description = "Time travelling car" }
  208. }
  209. }
  210. );
  211. tree.AddObject (
  212. new Road
  213. {
  214. Name = "Route 66",
  215. Description = "Great race course",
  216. Traffic = new List<Car>
  217. {
  218. new () { Name = "Pink Compact", Description = "Penelope Pitstop's car" },
  219. new () { Name = "Mean Machine", Description = "Dick Dastardly's car" }
  220. }
  221. }
  222. );
  223. tableView.Table = new TreeTableSource<IDescribedThing> (
  224. tableView,
  225. "Name",
  226. tree,
  227. new Dictionary<string, Func<IDescribedThing, object>> { { "Description", d => d.Description } }
  228. );
  229. tableView.BeginInit ();
  230. tableView.EndInit ();
  231. tableView.LayoutSubviews ();
  232. var top = new Toplevel ();
  233. top.Add (tableView);
  234. top.SetFocus ();
  235. Assert.Equal (tableView, top.MostFocused);
  236. return tableView;
  237. }
  238. private class Car : IDescribedThing
  239. {
  240. public string Name { get; set; }
  241. public string Description { get; set; }
  242. }
  243. private interface IDescribedThing
  244. {
  245. string Description { get; }
  246. string Name { get; }
  247. }
  248. private class Road : IDescribedThing
  249. {
  250. public List<Car> Traffic { get; set; }
  251. public string Name { get; set; }
  252. public string Description { get; set; }
  253. }
  254. }