TabViewTests.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. using System.Globalization;
  2. using Xunit.Abstractions;
  3. namespace Terminal.Gui.ViewsTests;
  4. public class TabViewTests
  5. {
  6. private readonly ITestOutputHelper _output;
  7. public TabViewTests (ITestOutputHelper output) { _output = output; }
  8. [Fact]
  9. public void AddTab_SameTabMoreThanOnce ()
  10. {
  11. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  12. Assert.Equal (2, tv.Tabs.Count);
  13. // Tab is already part of the control so shouldn't result in duplication
  14. tv.AddTab (tab1, false);
  15. tv.AddTab (tab1, false);
  16. tv.AddTab (tab1, false);
  17. tv.AddTab (tab1, false);
  18. Assert.Equal (2, tv.Tabs.Count);
  19. // Shutdown must be called to safely clean up Application if Init has been called
  20. Application.Shutdown ();
  21. }
  22. [Fact]
  23. public void AddTwoTabs_SecondIsSelected ()
  24. {
  25. InitFakeDriver ();
  26. var tv = new TabView ();
  27. Tab tab1;
  28. Tab tab2;
  29. tv.AddTab (tab1 = new Tab { DisplayText = "Tab1", View = new TextField { Text = "hi" } }, false);
  30. tv.AddTab (tab2 = new Tab { DisplayText = "Tab1", View = new Label { Text = "hi2" } }, true);
  31. Assert.Equal (2, tv.Tabs.Count);
  32. Assert.Equal (tab2, tv.SelectedTab);
  33. Application.Shutdown ();
  34. }
  35. [Fact]
  36. public void EnsureSelectedTabVisible_MustScroll ()
  37. {
  38. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  39. // Make tab width small to force only one tab visible at once
  40. tv.Width = 4;
  41. tv.SelectedTab = tab1;
  42. Assert.Equal (0, tv.TabScrollOffset);
  43. tv.EnsureSelectedTabIsVisible ();
  44. Assert.Equal (0, tv.TabScrollOffset);
  45. // Asking to show tab2 should automatically move scroll offset accordingly
  46. tv.SelectedTab = tab2;
  47. Assert.Equal (1, tv.TabScrollOffset);
  48. // Shutdown must be called to safely clean up Application if Init has been called
  49. Application.Shutdown ();
  50. }
  51. [Fact]
  52. public void EnsureSelectedTabVisible_NullSelect ()
  53. {
  54. TabView tv = GetTabView ();
  55. tv.SelectedTab = null;
  56. Assert.Null (tv.SelectedTab);
  57. Assert.Equal (0, tv.TabScrollOffset);
  58. tv.EnsureSelectedTabIsVisible ();
  59. Assert.Null (tv.SelectedTab);
  60. Assert.Equal (0, tv.TabScrollOffset);
  61. Application.Shutdown ();
  62. }
  63. [Fact]
  64. public void EnsureValidScrollOffsets_TabScrollOffset ()
  65. {
  66. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  67. // Make tab width small to force only one tab visible at once
  68. tv.Width = 4;
  69. tv.SelectedTab = tab1;
  70. Assert.Equal (0, tv.TabScrollOffset);
  71. tv.TabScrollOffset = 10;
  72. tv.SelectedTab = tab2;
  73. Assert.Equal (1, tv.TabScrollOffset);
  74. tv.TabScrollOffset = -1;
  75. tv.SelectedTab = tab1;
  76. Assert.Equal (0, tv.TabScrollOffset);
  77. // Shutdown must be called to safely clean up Application if Init has been called
  78. Application.Shutdown ();
  79. }
  80. [Fact]
  81. [AutoInitShutdown]
  82. public void MouseClick_ChangesTab ()
  83. {
  84. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  85. tv.Width = 20;
  86. tv.Height = 5;
  87. tv.LayoutSubviews ();
  88. tv.Draw ();
  89. View tabRow = tv.Subviews [0];
  90. Assert.Equal ("TabRowView", tabRow.GetType ().Name);
  91. TestHelpers.AssertDriverContentsAre (
  92. @"
  93. ╭────┬────╮
  94. │Tab1│Tab2│
  95. │ ╰────┴────────╮
  96. │hi │
  97. └──────────────────┘
  98. ",
  99. _output
  100. );
  101. Tab clicked = null;
  102. tv.TabClicked += (s, e) => { clicked = e.Tab; };
  103. var top = new Toplevel ();
  104. top.Add (tv);
  105. Application.Begin (top);
  106. MouseEvent args;
  107. // Waving mouse around does not trigger click
  108. for (var i = 0; i < 100; i++)
  109. {
  110. args = new MouseEvent { X = i, Y = 1, Flags = MouseFlags.ReportMousePosition };
  111. Application.OnMouseEvent (args);
  112. Application.Refresh ();
  113. Assert.Null (clicked);
  114. Assert.Equal (tab1, tv.SelectedTab);
  115. }
  116. args = new MouseEvent { X = 3, Y = 1, Flags = MouseFlags.Button1Clicked };
  117. Application.OnMouseEvent (args);
  118. Application.Refresh ();
  119. Assert.Equal (tab1, clicked);
  120. Assert.Equal (tab1, tv.SelectedTab);
  121. // Click to tab2
  122. args = new MouseEvent { X = 6, Y = 1, Flags = MouseFlags.Button1Clicked };
  123. Application.OnMouseEvent (args);
  124. Application.Refresh ();
  125. Assert.Equal (tab2, clicked);
  126. Assert.Equal (tab2, tv.SelectedTab);
  127. // cancel navigation
  128. tv.TabClicked += (s, e) =>
  129. {
  130. clicked = e.Tab;
  131. e.MouseEvent.Handled = true;
  132. };
  133. args = new MouseEvent { X = 3, Y = 1, Flags = MouseFlags.Button1Clicked };
  134. Application.OnMouseEvent (args);
  135. Application.Refresh ();
  136. // Tab 1 was clicked but event handler blocked navigation
  137. Assert.Equal (tab1, clicked);
  138. Assert.Equal (tab2, tv.SelectedTab);
  139. args = new MouseEvent { X = 12, Y = 1, Flags = MouseFlags.Button1Clicked };
  140. Application.OnMouseEvent (args);
  141. Application.Refresh ();
  142. // Clicking beyond last tab should raise event with null Tab
  143. Assert.Null (clicked);
  144. Assert.Equal (tab2, tv.SelectedTab);
  145. }
  146. [Fact]
  147. [AutoInitShutdown]
  148. public void MouseClick_Right_Left_Arrows_ChangesTab ()
  149. {
  150. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  151. tv.Width = 7;
  152. tv.Height = 5;
  153. tv.LayoutSubviews ();
  154. tv.Draw ();
  155. View tabRow = tv.Subviews [0];
  156. Assert.Equal ("TabRowView", tabRow.GetType ().Name);
  157. TestHelpers.AssertDriverContentsAre (
  158. @"
  159. ╭────╮
  160. │Tab1│
  161. │ ╰►
  162. │hi │
  163. └─────┘
  164. ",
  165. _output
  166. );
  167. Tab clicked = null;
  168. tv.TabClicked += (s, e) => { clicked = e.Tab; };
  169. Tab oldChanged = null;
  170. Tab newChanged = null;
  171. tv.SelectedTabChanged += (s, e) =>
  172. {
  173. oldChanged = e.OldTab;
  174. newChanged = e.NewTab;
  175. };
  176. var top = new Toplevel ();
  177. top.Add (tv);
  178. Application.Begin (top);
  179. // Click the right arrow
  180. var args = new MouseEvent { X = 6, Y = 2, Flags = MouseFlags.Button1Clicked };
  181. Application.OnMouseEvent (args);
  182. Application.Refresh ();
  183. Assert.Null (clicked);
  184. Assert.Equal (tab1, oldChanged);
  185. Assert.Equal (tab2, newChanged);
  186. Assert.Equal (tab2, tv.SelectedTab);
  187. TestHelpers.AssertDriverContentsAre (
  188. @"
  189. ╭────╮
  190. │Tab2│
  191. ◄ ╰╮
  192. │hi2 │
  193. └─────┘
  194. ",
  195. _output
  196. );
  197. // Click the left arrow
  198. args = new MouseEvent { X = 0, Y = 2, Flags = MouseFlags.Button1Clicked };
  199. Application.OnMouseEvent (args);
  200. Application.Refresh ();
  201. Assert.Null (clicked);
  202. Assert.Equal (tab2, oldChanged);
  203. Assert.Equal (tab1, newChanged);
  204. Assert.Equal (tab1, tv.SelectedTab);
  205. TestHelpers.AssertDriverContentsAre (
  206. @"
  207. ╭────╮
  208. │Tab1│
  209. │ ╰►
  210. │hi │
  211. └─────┘
  212. ",
  213. _output
  214. );
  215. }
  216. [Fact]
  217. [AutoInitShutdown]
  218. public void MouseClick_Right_Left_Arrows_ChangesTab_With_Border ()
  219. {
  220. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  221. tv.Width = 9;
  222. tv.Height = 7;
  223. Assert.Equal (LineStyle.None, tv.BorderStyle);
  224. tv.BorderStyle = LineStyle.Single;
  225. tv.LayoutSubviews ();
  226. tv.Draw ();
  227. View tabRow = tv.Subviews [0];
  228. Assert.Equal ("TabRowView", tabRow.GetType ().Name);
  229. TestHelpers.AssertDriverContentsAre (
  230. @"
  231. ┌───────┐
  232. │╭────╮ │
  233. ││Tab1│ │
  234. ││ ╰►│
  235. ││hi ││
  236. │└─────┘│
  237. └───────┘
  238. ",
  239. _output
  240. );
  241. Tab clicked = null;
  242. tv.TabClicked += (s, e) => { clicked = e.Tab; };
  243. Tab oldChanged = null;
  244. Tab newChanged = null;
  245. tv.SelectedTabChanged += (s, e) =>
  246. {
  247. oldChanged = e.OldTab;
  248. newChanged = e.NewTab;
  249. };
  250. var top = new Toplevel ();
  251. top.Add (tv);
  252. Application.Begin (top);
  253. // Click the right arrow
  254. var args = new MouseEvent { X = 7, Y = 3, Flags = MouseFlags.Button1Clicked };
  255. Application.OnMouseEvent (args);
  256. Application.Refresh ();
  257. Assert.Null (clicked);
  258. Assert.Equal (tab1, oldChanged);
  259. Assert.Equal (tab2, newChanged);
  260. Assert.Equal (tab2, tv.SelectedTab);
  261. TestHelpers.AssertDriverContentsAre (
  262. @"
  263. ┌───────┐
  264. │╭────╮ │
  265. ││Tab2│ │
  266. │◄ ╰╮│
  267. ││hi2 ││
  268. │└─────┘│
  269. └───────┘
  270. ",
  271. _output
  272. );
  273. // Click the left arrow
  274. args = new MouseEvent { X = 1, Y = 3, Flags = MouseFlags.Button1Clicked };
  275. Application.OnMouseEvent (args);
  276. Application.Refresh ();
  277. Assert.Null (clicked);
  278. Assert.Equal (tab2, oldChanged);
  279. Assert.Equal (tab1, newChanged);
  280. Assert.Equal (tab1, tv.SelectedTab);
  281. TestHelpers.AssertDriverContentsAre (
  282. @"
  283. ┌───────┐
  284. │╭────╮ │
  285. ││Tab1│ │
  286. ││ ╰►│
  287. ││hi ││
  288. │└─────┘│
  289. └───────┘
  290. ",
  291. _output
  292. );
  293. }
  294. [Fact]
  295. [AutoInitShutdown]
  296. public void ProcessKey_Down_Up_Right_Left_Home_End_PageDown_PageUp ()
  297. {
  298. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  299. tv.Width = 7;
  300. tv.Height = 5;
  301. var btn = new Button
  302. {
  303. Y = Pos.Bottom (tv) + 1,
  304. AutoSize = false,
  305. Height = 1,
  306. Width = 7,
  307. Text = "Ok"
  308. };
  309. Toplevel top = new ();
  310. top.Add (tv, btn);
  311. Application.Begin (top);
  312. // Is the selected tab view hosting focused
  313. Assert.Equal (tab1, tv.SelectedTab);
  314. Assert.Equal (tv, top.Focused);
  315. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  316. Assert.Equal (tv.SelectedTab.View, top.Focused.MostFocused);
  317. // Press the cursor up key to focus the selected tab
  318. var args = new Key (Key.CursorUp);
  319. Application.OnKeyDown (args);
  320. Application.Refresh ();
  321. // Is the selected tab focused
  322. Assert.Equal (tab1, tv.SelectedTab);
  323. Assert.Equal (tv, top.Focused);
  324. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  325. Tab oldChanged = null;
  326. Tab newChanged = null;
  327. tv.SelectedTabChanged += (s, e) =>
  328. {
  329. oldChanged = e.OldTab;
  330. newChanged = e.NewTab;
  331. };
  332. // Press the cursor right key to select the next tab
  333. args = new Key (Key.CursorRight);
  334. Application.OnKeyDown (args);
  335. Application.Refresh ();
  336. Assert.Equal (tab1, oldChanged);
  337. Assert.Equal (tab2, newChanged);
  338. Assert.Equal (tab2, tv.SelectedTab);
  339. Assert.Equal (tv, top.Focused);
  340. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  341. // Press the cursor down key to focus the selected tab view hosting
  342. args = new Key (Key.CursorDown);
  343. Application.OnKeyDown (args);
  344. Application.Refresh ();
  345. Assert.Equal (tab2, tv.SelectedTab);
  346. Assert.Equal (tv, top.Focused);
  347. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  348. // The tab view hosting is a label which can't be focused
  349. // and the View container is the focused one
  350. Assert.Equal (tv.Subviews [1], top.Focused.MostFocused);
  351. // Press the cursor down key again will focus next view in the toplevel
  352. Application.OnKeyDown (args);
  353. Application.Refresh ();
  354. Assert.Equal (tab2, tv.SelectedTab);
  355. Assert.Equal (btn, top.Focused);
  356. Assert.Null (tv.MostFocused);
  357. Assert.Null (top.Focused.MostFocused);
  358. // Press the cursor up key to focus the selected tab view hosting again
  359. args = new Key (Key.CursorUp);
  360. Application.OnKeyDown (args);
  361. Application.Refresh ();
  362. Assert.Equal (tab2, tv.SelectedTab);
  363. Assert.Equal (tv, top.Focused);
  364. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  365. // Press the cursor up key to focus the selected tab
  366. args = new Key (Key.CursorUp);
  367. Application.OnKeyDown (args);
  368. Application.Refresh ();
  369. // Is the selected tab focused
  370. Assert.Equal (tab2, tv.SelectedTab);
  371. Assert.Equal (tv, top.Focused);
  372. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  373. // Press the cursor left key to select the previous tab
  374. args = new Key (Key.CursorLeft);
  375. Application.OnKeyDown (args);
  376. Application.Refresh ();
  377. Assert.Equal (tab2, oldChanged);
  378. Assert.Equal (tab1, newChanged);
  379. Assert.Equal (tab1, tv.SelectedTab);
  380. Assert.Equal (tv, top.Focused);
  381. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  382. // Press the end key to select the last tab
  383. args = new Key (Key.End);
  384. Application.OnKeyDown (args);
  385. Application.Refresh ();
  386. Assert.Equal (tab1, oldChanged);
  387. Assert.Equal (tab2, newChanged);
  388. Assert.Equal (tab2, tv.SelectedTab);
  389. Assert.Equal (tv, top.Focused);
  390. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  391. // Press the home key to select the first tab
  392. args = new Key (Key.Home);
  393. Application.OnKeyDown (args);
  394. Application.Refresh ();
  395. Assert.Equal (tab2, oldChanged);
  396. Assert.Equal (tab1, newChanged);
  397. Assert.Equal (tab1, tv.SelectedTab);
  398. Assert.Equal (tv, top.Focused);
  399. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  400. // Press the page down key to select the next set of tabs
  401. args = new Key (Key.PageDown);
  402. Application.OnKeyDown (args);
  403. Application.Refresh ();
  404. Assert.Equal (tab1, oldChanged);
  405. Assert.Equal (tab2, newChanged);
  406. Assert.Equal (tab2, tv.SelectedTab);
  407. Assert.Equal (tv, top.Focused);
  408. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  409. // Press the page up key to select the previous set of tabs
  410. args = new Key (Key.PageUp);
  411. Application.OnKeyDown (args);
  412. Application.Refresh ();
  413. Assert.Equal (tab2, oldChanged);
  414. Assert.Equal (tab1, newChanged);
  415. Assert.Equal (tab1, tv.SelectedTab);
  416. Assert.Equal (tv, top.Focused);
  417. Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
  418. }
  419. [Fact]
  420. public void RemoveAllTabs_ClearsSelection ()
  421. {
  422. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  423. tv.SelectedTab = tab1;
  424. tv.RemoveTab (tab1);
  425. tv.RemoveTab (tab2);
  426. Assert.Null (tv.SelectedTab);
  427. // Shutdown must be called to safely clean up Application if Init has been called
  428. Application.Shutdown ();
  429. }
  430. [Fact]
  431. public void RemoveTab_ChangesSelection ()
  432. {
  433. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  434. tv.SelectedTab = tab1;
  435. tv.RemoveTab (tab1);
  436. Assert.Equal (tab2, tv.SelectedTab);
  437. // Shutdown must be called to safely clean up Application if Init has been called
  438. Application.Shutdown ();
  439. }
  440. [Fact]
  441. public void RemoveTab_MultipleCalls_NotAnError ()
  442. {
  443. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  444. tv.SelectedTab = tab1;
  445. // Repeated calls to remove a tab that is not part of
  446. // the collection should be ignored
  447. tv.RemoveTab (tab1);
  448. tv.RemoveTab (tab1);
  449. tv.RemoveTab (tab1);
  450. tv.RemoveTab (tab1);
  451. Assert.Equal (tab2, tv.SelectedTab);
  452. // Shutdown must be called to safely clean up Application if Init has been called
  453. Application.Shutdown ();
  454. }
  455. [Fact]
  456. public void SelectedTabChanged_Called ()
  457. {
  458. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  459. tv.SelectedTab = tab1;
  460. Tab oldTab = null;
  461. Tab newTab = null;
  462. var called = 0;
  463. tv.SelectedTabChanged += (s, e) =>
  464. {
  465. oldTab = e.OldTab;
  466. newTab = e.NewTab;
  467. called++;
  468. };
  469. tv.SelectedTab = tab2;
  470. Assert.Equal (1, called);
  471. Assert.Equal (tab1, oldTab);
  472. Assert.Equal (tab2, newTab);
  473. // Shutdown must be called to safely clean up Application if Init has been called
  474. Application.Shutdown ();
  475. }
  476. [Fact]
  477. [AutoInitShutdown]
  478. public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
  479. {
  480. TabView tv = GetTabView (out _, out _, false);
  481. tv.Width = 3;
  482. tv.Height = 5;
  483. tv.Style = new TabStyle { ShowTopLine = false };
  484. tv.ApplyStyleChanges ();
  485. tv.LayoutSubviews ();
  486. tv.Draw ();
  487. TestHelpers.AssertDriverContentsWithFrameAre (
  488. @"
  489. ││
  490. │╰►
  491. │h│
  492. │ │
  493. └─┘",
  494. _output
  495. );
  496. }
  497. [Fact]
  498. [AutoInitShutdown]
  499. public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
  500. {
  501. TabView tv = GetTabView (out _, out _, false);
  502. tv.Width = 4;
  503. tv.Height = 5;
  504. tv.Style = new TabStyle { ShowTopLine = false };
  505. tv.ApplyStyleChanges ();
  506. tv.LayoutSubviews ();
  507. tv.Draw ();
  508. TestHelpers.AssertDriverContentsWithFrameAre (
  509. @"
  510. │T│
  511. │ ╰►
  512. │hi│
  513. │ │
  514. └──┘",
  515. _output
  516. );
  517. }
  518. [Fact]
  519. [AutoInitShutdown]
  520. public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
  521. {
  522. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  523. tv.Width = 10;
  524. tv.Height = 5;
  525. tv.Style = new TabStyle { ShowTopLine = false };
  526. tv.ApplyStyleChanges ();
  527. // Ensures that the tab bar subview gets the bounds of the parent TabView
  528. tv.LayoutSubviews ();
  529. // Test two tab names that fit
  530. tab1.DisplayText = "12";
  531. tab2.DisplayText = "13";
  532. tv.Draw ();
  533. TestHelpers.AssertDriverContentsWithFrameAre (
  534. @"
  535. │12│13│
  536. │ ╰──┴──╮
  537. │hi │
  538. │ │
  539. └────────┘",
  540. _output
  541. );
  542. tv.SelectedTab = tab2;
  543. tv.Draw ();
  544. TestHelpers.AssertDriverContentsWithFrameAre (
  545. @"
  546. │12│13│
  547. ├──╯ ╰──╮
  548. │hi2 │
  549. │ │
  550. └────────┘",
  551. _output
  552. );
  553. tv.SelectedTab = tab1;
  554. // Test first tab name too long
  555. tab1.DisplayText = "12345678910";
  556. tab2.DisplayText = "13";
  557. tv.Draw ();
  558. TestHelpers.AssertDriverContentsWithFrameAre (
  559. @"
  560. │1234567│
  561. │ ╰►
  562. │hi │
  563. │ │
  564. └────────┘",
  565. _output
  566. );
  567. //switch to tab2
  568. tv.SelectedTab = tab2;
  569. tv.Draw ();
  570. TestHelpers.AssertDriverContentsWithFrameAre (
  571. @"
  572. │13│
  573. ◄ ╰─────╮
  574. │hi2 │
  575. │ │
  576. └────────┘",
  577. _output
  578. );
  579. // now make both tabs too long
  580. tab1.DisplayText = "12345678910";
  581. tab2.DisplayText = "abcdefghijklmnopq";
  582. tv.Draw ();
  583. TestHelpers.AssertDriverContentsWithFrameAre (
  584. @"
  585. │abcdefg│
  586. ◄ ╰╮
  587. │hi2 │
  588. │ │
  589. └────────┘",
  590. _output
  591. );
  592. }
  593. [Fact]
  594. [AutoInitShutdown]
  595. public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
  596. {
  597. TabView tv = GetTabView (out _, out _, false);
  598. tv.Width = 3;
  599. tv.Height = 5;
  600. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  601. tv.ApplyStyleChanges ();
  602. tv.LayoutSubviews ();
  603. tv.Draw ();
  604. TestHelpers.AssertDriverContentsWithFrameAre (
  605. @"
  606. ┌─┐
  607. │h│
  608. │ │
  609. │╭►
  610. ││ ",
  611. _output
  612. );
  613. }
  614. [Fact]
  615. [AutoInitShutdown]
  616. public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
  617. {
  618. TabView tv = GetTabView (out _, out _, false);
  619. tv.Width = 4;
  620. tv.Height = 5;
  621. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  622. tv.ApplyStyleChanges ();
  623. tv.LayoutSubviews ();
  624. tv.Draw ();
  625. TestHelpers.AssertDriverContentsWithFrameAre (
  626. @"
  627. ┌──┐
  628. │hi│
  629. │ │
  630. │ ╭►
  631. │T│ ",
  632. _output
  633. );
  634. }
  635. [Fact]
  636. [AutoInitShutdown]
  637. public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
  638. {
  639. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  640. tv.Width = 10;
  641. tv.Height = 5;
  642. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  643. tv.ApplyStyleChanges ();
  644. // Ensures that the tab bar subview gets the bounds of the parent TabView
  645. tv.LayoutSubviews ();
  646. // Test two tab names that fit
  647. tab1.DisplayText = "12";
  648. tab2.DisplayText = "13";
  649. tv.Draw ();
  650. TestHelpers.AssertDriverContentsWithFrameAre (
  651. @"
  652. ┌────────┐
  653. │hi │
  654. │ │
  655. │ ╭──┬──╯
  656. │12│13│ ",
  657. _output
  658. );
  659. tv.SelectedTab = tab2;
  660. tv.Draw ();
  661. TestHelpers.AssertDriverContentsWithFrameAre (
  662. @"
  663. ┌────────┐
  664. │hi2 │
  665. │ │
  666. ├──╮ ╭──╯
  667. │12│13│ ",
  668. _output
  669. );
  670. tv.SelectedTab = tab1;
  671. // Test first tab name too long
  672. tab1.DisplayText = "12345678910";
  673. tab2.DisplayText = "13";
  674. tv.Draw ();
  675. TestHelpers.AssertDriverContentsWithFrameAre (
  676. @"
  677. ┌────────┐
  678. │hi │
  679. │ │
  680. │ ╭►
  681. │1234567│ ",
  682. _output
  683. );
  684. //switch to tab2
  685. tv.SelectedTab = tab2;
  686. tv.Draw ();
  687. TestHelpers.AssertDriverContentsWithFrameAre (
  688. @"
  689. ┌────────┐
  690. │hi2 │
  691. │ │
  692. ◄ ╭─────╯
  693. │13│ ",
  694. _output
  695. );
  696. // now make both tabs too long
  697. tab1.DisplayText = "12345678910";
  698. tab2.DisplayText = "abcdefghijklmnopq";
  699. tv.Draw ();
  700. TestHelpers.AssertDriverContentsWithFrameAre (
  701. @"
  702. ┌────────┐
  703. │hi2 │
  704. │ │
  705. ◄ ╭╯
  706. │abcdefg│ ",
  707. _output
  708. );
  709. }
  710. [Fact]
  711. [AutoInitShutdown]
  712. public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width3 ()
  713. {
  714. TabView tv = GetTabView (out _, out _, false);
  715. tv.Width = 3;
  716. tv.Height = 5;
  717. tv.LayoutSubviews ();
  718. tv.Draw ();
  719. TestHelpers.AssertDriverContentsWithFrameAre (
  720. @"
  721. ╭╮
  722. ││
  723. │╰►
  724. │h│
  725. └─┘",
  726. _output
  727. );
  728. }
  729. [Fact]
  730. [AutoInitShutdown]
  731. public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width4 ()
  732. {
  733. TabView tv = GetTabView (out _, out _, false);
  734. tv.Width = 4;
  735. tv.Height = 5;
  736. tv.LayoutSubviews ();
  737. tv.Draw ();
  738. TestHelpers.AssertDriverContentsWithFrameAre (
  739. @"
  740. ╭─╮
  741. │T│
  742. │ ╰►
  743. │hi│
  744. └──┘",
  745. _output
  746. );
  747. }
  748. [Fact]
  749. [AutoInitShutdown]
  750. public void ShowTopLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
  751. {
  752. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  753. tv.Width = 10;
  754. tv.Height = 5;
  755. // Ensures that the tab bar subview gets the bounds of the parent TabView
  756. tv.LayoutSubviews ();
  757. // Test two tab names that fit
  758. tab1.DisplayText = "12";
  759. tab2.DisplayText = "13";
  760. tv.Draw ();
  761. TestHelpers.AssertDriverContentsWithFrameAre (
  762. @"
  763. ╭──┬──╮
  764. │12│13│
  765. │ ╰──┴──╮
  766. │hi │
  767. └────────┘",
  768. _output
  769. );
  770. tv.SelectedTab = tab2;
  771. tv.Draw ();
  772. TestHelpers.AssertDriverContentsWithFrameAre (
  773. @"
  774. ╭──┬──╮
  775. │12│13│
  776. ├──╯ ╰──╮
  777. │hi2 │
  778. └────────┘",
  779. _output
  780. );
  781. tv.SelectedTab = tab1;
  782. // Test first tab name too long
  783. tab1.DisplayText = "12345678910";
  784. tab2.DisplayText = "13";
  785. tv.Draw ();
  786. TestHelpers.AssertDriverContentsWithFrameAre (
  787. @"
  788. ╭───────╮
  789. │1234567│
  790. │ ╰►
  791. │hi │
  792. └────────┘",
  793. _output
  794. );
  795. //switch to tab2
  796. tv.SelectedTab = tab2;
  797. tv.Draw ();
  798. TestHelpers.AssertDriverContentsWithFrameAre (
  799. @"
  800. ╭──╮
  801. │13│
  802. ◄ ╰─────╮
  803. │hi2 │
  804. └────────┘",
  805. _output
  806. );
  807. // now make both tabs too long
  808. tab1.DisplayText = "12345678910";
  809. tab2.DisplayText = "abcdefghijklmnopq";
  810. tv.Draw ();
  811. TestHelpers.AssertDriverContentsWithFrameAre (
  812. @"
  813. ╭───────╮
  814. │abcdefg│
  815. ◄ ╰╮
  816. │hi2 │
  817. └────────┘",
  818. _output
  819. );
  820. }
  821. [Fact]
  822. [AutoInitShutdown]
  823. public void ShowTopLine_True_TabsOnBottom_False_With_Unicode ()
  824. {
  825. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  826. tv.Width = 20;
  827. tv.Height = 5;
  828. tv.LayoutSubviews ();
  829. tab1.DisplayText = "Tab0";
  830. tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
  831. tv.Draw ();
  832. TestHelpers.AssertDriverContentsWithFrameAre (
  833. @"
  834. ╭────╮
  835. │Tab0│
  836. │ ╰─────────────►
  837. │hi │
  838. └──────────────────┘",
  839. _output
  840. );
  841. tv.SelectedTab = tab2;
  842. tv.Draw ();
  843. TestHelpers.AssertDriverContentsWithFrameAre (
  844. @"
  845. ╭──────────────╮
  846. │Les Misérables│
  847. ◄ ╰───╮
  848. │hi2 │
  849. └──────────────────┘",
  850. _output
  851. );
  852. }
  853. [Fact]
  854. [AutoInitShutdown]
  855. public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
  856. {
  857. TabView tv = GetTabView (out _, out _, false);
  858. tv.Width = 3;
  859. tv.Height = 5;
  860. tv.Style = new TabStyle { TabsOnBottom = true };
  861. tv.ApplyStyleChanges ();
  862. tv.LayoutSubviews ();
  863. tv.Draw ();
  864. TestHelpers.AssertDriverContentsWithFrameAre (
  865. @"
  866. ┌─┐
  867. │h│
  868. │╭►
  869. ││
  870. ╰╯ ",
  871. _output
  872. );
  873. }
  874. [Fact]
  875. [AutoInitShutdown]
  876. public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
  877. {
  878. TabView tv = GetTabView (out _, out _, false);
  879. tv.Width = 4;
  880. tv.Height = 5;
  881. tv.Style = new TabStyle { TabsOnBottom = true };
  882. tv.ApplyStyleChanges ();
  883. tv.LayoutSubviews ();
  884. tv.Draw ();
  885. TestHelpers.AssertDriverContentsWithFrameAre (
  886. @"
  887. ┌──┐
  888. │hi│
  889. │ ╭►
  890. │T│
  891. ╰─╯ ",
  892. _output
  893. );
  894. }
  895. [Fact]
  896. [AutoInitShutdown]
  897. public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
  898. {
  899. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  900. tv.Width = 10;
  901. tv.Height = 5;
  902. tv.Style = new TabStyle { TabsOnBottom = true };
  903. tv.ApplyStyleChanges ();
  904. // Ensures that the tab bar subview gets the bounds of the parent TabView
  905. tv.LayoutSubviews ();
  906. // Test two tab names that fit
  907. tab1.DisplayText = "12";
  908. tab2.DisplayText = "13";
  909. tv.Draw ();
  910. TestHelpers.AssertDriverContentsWithFrameAre (
  911. @"
  912. ┌────────┐
  913. │hi │
  914. │ ╭──┬──╯
  915. │12│13│
  916. ╰──┴──╯ ",
  917. _output
  918. );
  919. // Test first tab name too long
  920. tab1.DisplayText = "12345678910";
  921. tab2.DisplayText = "13";
  922. tv.Draw ();
  923. TestHelpers.AssertDriverContentsWithFrameAre (
  924. @"
  925. ┌────────┐
  926. │hi │
  927. │ ╭►
  928. │1234567│
  929. ╰───────╯ ",
  930. _output
  931. );
  932. //switch to tab2
  933. tv.SelectedTab = tab2;
  934. tv.Draw ();
  935. TestHelpers.AssertDriverContentsWithFrameAre (
  936. @"
  937. ┌────────┐
  938. │hi2 │
  939. ◄ ╭─────╯
  940. │13│
  941. ╰──╯ ",
  942. _output
  943. );
  944. // now make both tabs too long
  945. tab1.DisplayText = "12345678910";
  946. tab2.DisplayText = "abcdefghijklmnopq";
  947. tv.Draw ();
  948. TestHelpers.AssertDriverContentsWithFrameAre (
  949. @"
  950. ┌────────┐
  951. │hi2 │
  952. ◄ ╭╯
  953. │abcdefg│
  954. ╰───────╯ ",
  955. _output
  956. );
  957. }
  958. [Fact]
  959. [AutoInitShutdown]
  960. public void ShowTopLine_True_TabsOnBottom_True_With_Unicode ()
  961. {
  962. TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
  963. tv.Width = 20;
  964. tv.Height = 5;
  965. tv.Style = new TabStyle { TabsOnBottom = true };
  966. tv.ApplyStyleChanges ();
  967. tv.LayoutSubviews ();
  968. tab1.DisplayText = "Tab0";
  969. tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
  970. tv.Draw ();
  971. TestHelpers.AssertDriverContentsWithFrameAre (
  972. @"
  973. ┌──────────────────┐
  974. │hi │
  975. │ ╭─────────────►
  976. │Tab0│
  977. ╰────╯ ",
  978. _output
  979. );
  980. tv.SelectedTab = tab2;
  981. tv.Draw ();
  982. TestHelpers.AssertDriverContentsWithFrameAre (
  983. @"
  984. ┌──────────────────┐
  985. │hi2 │
  986. ◄ ╭───╯
  987. │Les Misérables│
  988. ╰──────────────╯ ",
  989. _output
  990. );
  991. }
  992. [Fact]
  993. public void SwitchTabBy_NormalUsage ()
  994. {
  995. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  996. Tab tab3;
  997. Tab tab4;
  998. Tab tab5;
  999. tv.AddTab (tab3 = new Tab (), false);
  1000. tv.AddTab (tab4 = new Tab (), false);
  1001. tv.AddTab (tab5 = new Tab (), false);
  1002. tv.SelectedTab = tab1;
  1003. var called = 0;
  1004. tv.SelectedTabChanged += (s, e) => { called++; };
  1005. tv.SwitchTabBy (1);
  1006. Assert.Equal (1, called);
  1007. Assert.Equal (tab2, tv.SelectedTab);
  1008. //reset called counter
  1009. called = 0;
  1010. // go right 2
  1011. tv.SwitchTabBy (2);
  1012. // even though we go right 2 indexes the event should only be called once
  1013. Assert.Equal (1, called);
  1014. Assert.Equal (tab4, tv.SelectedTab);
  1015. // Shutdown must be called to safely clean up Application if Init has been called
  1016. Application.Shutdown ();
  1017. }
  1018. [Fact]
  1019. public void SwitchTabBy_OutOfTabsRange ()
  1020. {
  1021. TabView tv = GetTabView (out Tab tab1, out Tab tab2);
  1022. tv.SelectedTab = tab1;
  1023. tv.SwitchTabBy (500);
  1024. Assert.Equal (tab2, tv.SelectedTab);
  1025. tv.SwitchTabBy (-500);
  1026. Assert.Equal (tab1, tv.SelectedTab);
  1027. // Shutdown must be called to safely clean up Application if Init has been called
  1028. Application.Shutdown ();
  1029. }
  1030. private TabView GetTabView () { return GetTabView (out _, out _); }
  1031. private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true)
  1032. {
  1033. if (initFakeDriver)
  1034. {
  1035. InitFakeDriver ();
  1036. }
  1037. var tv = new TabView ();
  1038. tv.BeginInit ();
  1039. tv.EndInit ();
  1040. tv.ColorScheme = new ColorScheme ();
  1041. tv.AddTab (
  1042. tab1 = new Tab { DisplayText = "Tab1", View = new TextField { Width = 2, Text = "hi" } },
  1043. false
  1044. );
  1045. tv.AddTab (tab2 = new Tab { DisplayText = "Tab2", View = new Label { Text = "hi2" } }, false);
  1046. return tv;
  1047. }
  1048. private void InitFakeDriver ()
  1049. {
  1050. var driver = new FakeDriver ();
  1051. Application.Init (driver);
  1052. driver.Init ();
  1053. }
  1054. }