TabViewTests.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Terminal.Gui;
  7. using Xunit;
  8. using System.Globalization;
  9. using Xunit.Abstractions;
  10. namespace Terminal.Gui.Views {
  11. public class TabViewTests {
  12. readonly ITestOutputHelper output;
  13. public TabViewTests (ITestOutputHelper output)
  14. {
  15. this.output = output;
  16. }
  17. private TabView GetTabView ()
  18. {
  19. return GetTabView (out _, out _);
  20. }
  21. private TabView GetTabView (out TabView.Tab tab1, out TabView.Tab tab2, bool initFakeDriver = true)
  22. {
  23. if (initFakeDriver)
  24. InitFakeDriver ();
  25. var tv = new TabView ();
  26. tv.ColorScheme = new ColorScheme ();
  27. tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false);
  28. tv.AddTab (tab2 = new TabView.Tab ("Tab2", new Label ("hi2")), false);
  29. return tv;
  30. }
  31. [Fact]
  32. public void AddTwoTabs_SecondIsSelected ()
  33. {
  34. InitFakeDriver ();
  35. var tv = new TabView ();
  36. TabView.Tab tab1;
  37. TabView.Tab tab2;
  38. tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false);
  39. tv.AddTab (tab2 = new TabView.Tab ("Tab1", new Label ("hi2")), true);
  40. Assert.Equal (2, tv.Tabs.Count);
  41. Assert.Equal (tab2, tv.SelectedTab);
  42. Application.Shutdown ();
  43. }
  44. [Fact]
  45. public void EnsureSelectedTabVisible_NullSelect ()
  46. {
  47. var tv = GetTabView ();
  48. tv.SelectedTab = null;
  49. Assert.Null (tv.SelectedTab);
  50. Assert.Equal (0, tv.TabScrollOffset);
  51. tv.EnsureSelectedTabIsVisible ();
  52. Assert.Null (tv.SelectedTab);
  53. Assert.Equal (0, tv.TabScrollOffset);
  54. Application.Shutdown ();
  55. }
  56. [Fact]
  57. public void EnsureSelectedTabVisible_MustScroll ()
  58. {
  59. var tv = GetTabView (out var tab1, out var tab2);
  60. // Make tab width small to force only one tab visible at once
  61. tv.Width = 4;
  62. tv.SelectedTab = tab1;
  63. Assert.Equal (0, tv.TabScrollOffset);
  64. tv.EnsureSelectedTabIsVisible ();
  65. Assert.Equal (0, tv.TabScrollOffset);
  66. // Asking to show tab2 should automatically move scroll offset accordingly
  67. tv.SelectedTab = tab2;
  68. Assert.Equal (1, tv.TabScrollOffset);
  69. // Shutdown must be called to safely clean up Application if Init has been called
  70. Application.Shutdown ();
  71. }
  72. [Fact]
  73. public void SelectedTabChanged_Called ()
  74. {
  75. var tv = GetTabView (out var tab1, out var tab2);
  76. tv.SelectedTab = tab1;
  77. TabView.Tab oldTab = null;
  78. TabView.Tab newTab = null;
  79. int called = 0;
  80. tv.SelectedTabChanged += (s, e) => {
  81. oldTab = e.OldTab;
  82. newTab = e.NewTab;
  83. called++;
  84. };
  85. tv.SelectedTab = tab2;
  86. Assert.Equal (1, called);
  87. Assert.Equal (tab1, oldTab);
  88. Assert.Equal (tab2, newTab);
  89. // Shutdown must be called to safely clean up Application if Init has been called
  90. Application.Shutdown ();
  91. }
  92. [Fact]
  93. public void RemoveTab_ChangesSelection ()
  94. {
  95. var tv = GetTabView (out var tab1, out var tab2);
  96. tv.SelectedTab = tab1;
  97. tv.RemoveTab (tab1);
  98. Assert.Equal (tab2, tv.SelectedTab);
  99. // Shutdown must be called to safely clean up Application if Init has been called
  100. Application.Shutdown ();
  101. }
  102. [Fact]
  103. public void RemoveTab_MultipleCalls_NotAnError ()
  104. {
  105. var tv = GetTabView (out var tab1, out var tab2);
  106. tv.SelectedTab = tab1;
  107. // Repeated calls to remove a tab that is not part of
  108. // the collection should be ignored
  109. tv.RemoveTab (tab1);
  110. tv.RemoveTab (tab1);
  111. tv.RemoveTab (tab1);
  112. tv.RemoveTab (tab1);
  113. Assert.Equal (tab2, tv.SelectedTab);
  114. // Shutdown must be called to safely clean up Application if Init has been called
  115. Application.Shutdown ();
  116. }
  117. [Fact]
  118. public void RemoveAllTabs_ClearsSelection ()
  119. {
  120. var tv = GetTabView (out var tab1, out var tab2);
  121. tv.SelectedTab = tab1;
  122. tv.RemoveTab (tab1);
  123. tv.RemoveTab (tab2);
  124. Assert.Null (tv.SelectedTab);
  125. // Shutdown must be called to safely clean up Application if Init has been called
  126. Application.Shutdown ();
  127. }
  128. [Fact]
  129. public void SwitchTabBy_NormalUsage ()
  130. {
  131. var tv = GetTabView (out var tab1, out var tab2);
  132. TabView.Tab tab3;
  133. TabView.Tab tab4;
  134. TabView.Tab tab5;
  135. tv.AddTab (tab3 = new TabView.Tab (), false);
  136. tv.AddTab (tab4 = new TabView.Tab (), false);
  137. tv.AddTab (tab5 = new TabView.Tab (), false);
  138. tv.SelectedTab = tab1;
  139. int called = 0;
  140. tv.SelectedTabChanged += (s, e) => { called++; };
  141. tv.SwitchTabBy (1);
  142. Assert.Equal (1, called);
  143. Assert.Equal (tab2, tv.SelectedTab);
  144. //reset called counter
  145. called = 0;
  146. // go right 2
  147. tv.SwitchTabBy (2);
  148. // even though we go right 2 indexes the event should only be called once
  149. Assert.Equal (1, called);
  150. Assert.Equal (tab4, tv.SelectedTab);
  151. // Shutdown must be called to safely clean up Application if Init has been called
  152. Application.Shutdown ();
  153. }
  154. [Fact]
  155. public void AddTab_SameTabMoreThanOnce ()
  156. {
  157. var tv = GetTabView (out var tab1, out var tab2);
  158. Assert.Equal (2, tv.Tabs.Count);
  159. // Tab is already part of the control so shouldn't result in duplication
  160. tv.AddTab (tab1, false);
  161. tv.AddTab (tab1, false);
  162. tv.AddTab (tab1, false);
  163. tv.AddTab (tab1, false);
  164. Assert.Equal (2, tv.Tabs.Count);
  165. // Shutdown must be called to safely clean up Application if Init has been called
  166. Application.Shutdown ();
  167. }
  168. [Fact]
  169. public void SwitchTabBy_OutOfTabsRange ()
  170. {
  171. var tv = GetTabView (out var tab1, out var tab2);
  172. tv.SelectedTab = tab1;
  173. tv.SwitchTabBy (500);
  174. Assert.Equal (tab2, tv.SelectedTab);
  175. tv.SwitchTabBy (-500);
  176. Assert.Equal (tab1, tv.SelectedTab);
  177. // Shutdown must be called to safely clean up Application if Init has been called
  178. Application.Shutdown ();
  179. }
  180. [Fact, AutoInitShutdown]
  181. public void TestThinTabView_WithLongNames ()
  182. {
  183. var tv = GetTabView (out var tab1, out var tab2, false);
  184. tv.Width = 10;
  185. tv.Height = 5;
  186. // Ensures that the tab bar subview gets the bounds of the parent TabView
  187. tv.LayoutSubviews ();
  188. // Test two tab names that fit
  189. tab1.Text = "12";
  190. tab2.Text = "13";
  191. tv.Redraw (tv.Bounds);
  192. GraphViewTests.AssertDriverContentsAre (@"
  193. ┌──┐
  194. │12│13
  195. │ └─────┐
  196. │hi │
  197. └────────┘", output);
  198. // Test first tab name too long
  199. tab1.Text = "12345678910";
  200. tab2.Text = "13";
  201. tv.Redraw (tv.Bounds);
  202. GraphViewTests.AssertDriverContentsAre (@"
  203. ┌───────┐
  204. │1234567│
  205. │ └►
  206. │hi │
  207. └────────┘", output);
  208. //switch to tab2
  209. tv.SelectedTab = tab2;
  210. tv.Redraw (tv.Bounds);
  211. GraphViewTests.AssertDriverContentsAre (@"
  212. ┌──┐
  213. │13│
  214. ◄ └─────┐
  215. │hi2 │
  216. └────────┘", output);
  217. // now make both tabs too long
  218. tab1.Text = "12345678910";
  219. tab2.Text = "abcdefghijklmnopq";
  220. tv.Redraw (tv.Bounds);
  221. GraphViewTests.AssertDriverContentsAre (@"
  222. ┌───────┐
  223. │abcdefg│
  224. ◄ └┐
  225. │hi2 │
  226. └────────┘", output);
  227. }
  228. [Fact, AutoInitShutdown]
  229. public void TestTabView_Width4 ()
  230. {
  231. var tv = GetTabView (out _, out _, false);
  232. tv.Width = 4;
  233. tv.Height = 5;
  234. tv.LayoutSubviews ();
  235. tv.Redraw (tv.Bounds);
  236. GraphViewTests.AssertDriverContentsAre (@"
  237. ┌─┐
  238. │T│
  239. │ └►
  240. │hi│
  241. └──┘", output);
  242. }
  243. [Fact, AutoInitShutdown]
  244. public void TestTabView_Width3 ()
  245. {
  246. var tv = GetTabView (out _, out _, false);
  247. tv.Width = 3;
  248. tv.Height = 5;
  249. tv.LayoutSubviews ();
  250. tv.Redraw (tv.Bounds);
  251. GraphViewTests.AssertDriverContentsAre (@"
  252. ┌─┐
  253. │h│
  254. └─┘", output);
  255. }
  256. private void InitFakeDriver ()
  257. {
  258. var driver = new FakeDriver ();
  259. Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
  260. driver.Init (() => { });
  261. }
  262. }
  263. }