TreeTableSourceTests.cs 11 KB

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