TreeTableSourceTests.cs 11 KB

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