MenuBarv2Tests.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. using System.Globalization;
  2. using System.Reflection;
  3. using TerminalGuiFluentTesting;
  4. using TerminalGuiFluentTestingXunit;
  5. using Xunit.Abstractions;
  6. namespace IntegrationTests.FluentTests;
  7. /// <summary>
  8. /// Tests for the MenuBarv2 class
  9. /// </summary>
  10. public class MenuBarv2Tests
  11. {
  12. private readonly TextWriter _out;
  13. public MenuBarv2Tests (ITestOutputHelper outputHelper)
  14. {
  15. CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
  16. _out = new TestOutputWriter (outputHelper);
  17. }
  18. [Theory]
  19. [ClassData (typeof (V2TestDrivers))]
  20. public void Initializes_WithNoItems (V2TestDriver d)
  21. {
  22. using GuiTestContext c = With.A<Window> (80, 25, d)
  23. .Then (
  24. () =>
  25. {
  26. // Create a menu bar with no items
  27. var menuBar = new MenuBarv2 ();
  28. Assert.Empty (menuBar.SubViews);
  29. Assert.False (menuBar.CanFocus);
  30. Assert.Equal (Orientation.Horizontal, menuBar.Orientation);
  31. Assert.Equal (Key.F9, MenuBarv2.DefaultKey);
  32. })
  33. .WriteOutLogs (_out)
  34. .Stop ();
  35. }
  36. [Theory]
  37. [ClassData (typeof (V2TestDrivers))]
  38. public void Initializes_WithItems (V2TestDriver d)
  39. {
  40. MenuBarItemv2 [] menuItems = [];
  41. using GuiTestContext c = With.A<Window> (80, 25, d)
  42. .Then (
  43. () =>
  44. {
  45. // Create items for the menu bar
  46. menuItems =
  47. [
  48. new (
  49. "_File",
  50. [
  51. new MenuItemv2 ("_Open", "Opens a file", () => { })
  52. ]),
  53. new (
  54. "_Edit",
  55. [
  56. new MenuItemv2 ("_Copy", "Copies selection", () => { })
  57. ])
  58. ];
  59. var menuBar = new MenuBarv2 (menuItems);
  60. Assert.Equal (2, menuBar.SubViews.Count);
  61. // First item should be the File menu
  62. var fileMenu = menuBar.SubViews.ElementAt (0) as MenuBarItemv2;
  63. Assert.NotNull (fileMenu);
  64. Assert.Equal ("_File", fileMenu.Title);
  65. // Second item should be the Edit menu
  66. var editMenu = menuBar.SubViews.ElementAt (1) as MenuBarItemv2;
  67. Assert.NotNull (editMenu);
  68. Assert.Equal ("_Edit", editMenu.Title);
  69. })
  70. .WriteOutLogs (_out)
  71. .Stop ();
  72. }
  73. [Theory]
  74. [ClassData (typeof (V2TestDrivers))]
  75. public void AddsItems_WithMenusProperty (V2TestDriver d)
  76. {
  77. using GuiTestContext c = With.A<Window> (80, 25, d)
  78. .Then (
  79. () =>
  80. {
  81. var menuBar = new MenuBarv2 ();
  82. // Set items through Menus property
  83. menuBar.Menus =
  84. [
  85. new ("_File"),
  86. new ("_Edit"),
  87. new ("_View")
  88. ];
  89. Assert.Equal (3, menuBar.SubViews.Count);
  90. })
  91. .WriteOutLogs (_out)
  92. .Stop ();
  93. }
  94. [Theory]
  95. [ClassData (typeof (V2TestDrivers))]
  96. public void ChangesKey_RaisesEvent (V2TestDriver d)
  97. {
  98. using GuiTestContext c = With.A<Window> (80, 25, d)
  99. .Then (
  100. () =>
  101. {
  102. var menuBar = new MenuBarv2 ();
  103. var oldKeyValue = Key.Empty;
  104. var newKeyValue = Key.Empty;
  105. var eventRaised = false;
  106. menuBar.KeyChanged += (_, args) =>
  107. {
  108. eventRaised = true;
  109. oldKeyValue = args.OldKey;
  110. newKeyValue = args.NewKey;
  111. };
  112. // Default key should be F9
  113. Assert.Equal (Key.F9, menuBar.Key);
  114. // Change key to F1
  115. menuBar.Key = Key.F1;
  116. // Verify event was raised
  117. Assert.True (eventRaised);
  118. Assert.Equal (Key.F9, oldKeyValue);
  119. Assert.Equal (Key.F1, newKeyValue);
  120. // Verify key was changed
  121. Assert.Equal (Key.F1, menuBar.Key);
  122. })
  123. .WriteOutLogs (_out)
  124. .Stop ();
  125. }
  126. [Theory]
  127. [ClassData (typeof (V2TestDrivers))]
  128. public void DefaultKey_Activates (V2TestDriver d)
  129. {
  130. MenuBarv2? menuBar = null;
  131. using GuiTestContext c = With.A<Window> (50, 20, d)
  132. .Then (
  133. () =>
  134. {
  135. menuBar = new MenuBarv2 ();
  136. Toplevel top = Application.Top!;
  137. top.Add (
  138. new View ()
  139. {
  140. CanFocus = true,
  141. Id = "focusableView",
  142. });
  143. menuBar.EnableForDesign (ref top);
  144. Application.Top!.Add (menuBar);
  145. })
  146. .WaitIteration ()
  147. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  148. .ScreenShot ("MenuBar initial state", _out)
  149. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  150. .WaitIteration ()
  151. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  152. .WriteOutLogs (_out)
  153. .AssertEqual ("_New file", Application.Navigation!.GetFocused ()!.Title)
  154. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  155. .AssertTrue (menuBar?.IsOpen ())
  156. .WriteOutLogs (_out)
  157. .Stop ();
  158. }
  159. [Theory]
  160. [ClassData (typeof (V2TestDrivers))]
  161. public void DefaultKey_DeActivates (V2TestDriver d)
  162. {
  163. MenuBarv2? menuBar = null;
  164. using GuiTestContext c = With.A<Window> (50, 20, d)
  165. .Then (
  166. () =>
  167. {
  168. menuBar = new MenuBarv2 ();
  169. Toplevel top = Application.Top!;
  170. top.Add (
  171. new View ()
  172. {
  173. CanFocus = true,
  174. Id = "focusableView",
  175. });
  176. menuBar.EnableForDesign (ref top);
  177. Application.Top!.Add (menuBar);
  178. })
  179. .WaitIteration ()
  180. .AssertIsNotType<MenuItemv2>(Application.Navigation!.GetFocused())
  181. .ScreenShot ("MenuBar initial state", _out)
  182. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  183. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  184. .AssertEqual ("_New file", Application.Navigation!.GetFocused ()!.Title)
  185. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  186. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  187. .AssertIsNotType<MenuItemv2>(Application.Navigation!.GetFocused())
  188. .WriteOutLogs (_out)
  189. .Stop ();
  190. }
  191. [Theory]
  192. [ClassData (typeof (V2TestDrivers))]
  193. public void ShowHidePopovers (V2TestDriver d)
  194. {
  195. using GuiTestContext c = With.A<Window> (80, 25, d)
  196. .Then (
  197. () =>
  198. {
  199. // Create a menu bar with items that have submenus
  200. var fileMenuItem = new MenuBarItemv2 (
  201. "_File",
  202. [
  203. new MenuItemv2 ("_Open", string.Empty, null),
  204. new MenuItemv2 ("_Save", string.Empty, null)
  205. ]);
  206. var menuBar = new MenuBarv2 ([fileMenuItem]);
  207. // Initially, no menu should be open
  208. Assert.False (menuBar.IsOpen ());
  209. Assert.False (menuBar.Active);
  210. // Initialize the menu bar
  211. menuBar.BeginInit ();
  212. menuBar.EndInit ();
  213. // Simulate showing a popover menu by manipulating the first menu item
  214. MethodInfo? showPopoverMethod = typeof (MenuBarv2).GetMethod (
  215. "ShowPopover",
  216. BindingFlags.NonPublic | BindingFlags.Instance);
  217. // Set menu bar to active state using reflection
  218. FieldInfo? activeField = typeof (MenuBarv2).GetField (
  219. "_active",
  220. BindingFlags.NonPublic | BindingFlags.Instance);
  221. activeField?.SetValue (menuBar, true);
  222. menuBar.CanFocus = true;
  223. // Show the popover menu
  224. showPopoverMethod?.Invoke (menuBar, new object? [] { fileMenuItem });
  225. // Should be active now
  226. Assert.True (menuBar.Active);
  227. // Test if we can hide the popover menu
  228. fileMenuItem.PopoverMenu!.Visible = true;
  229. Assert.True (menuBar.HideActiveItem ());
  230. // Menu should no longer be open or active
  231. Assert.False (menuBar.Active);
  232. Assert.False (menuBar.IsOpen ());
  233. Assert.False (menuBar.CanFocus);
  234. })
  235. .WriteOutLogs (_out)
  236. .Stop ();
  237. }
  238. [Theory]
  239. [ClassData (typeof (V2TestDrivers))]
  240. public void EnableForDesign_CreatesMenuItems (V2TestDriver d)
  241. {
  242. using GuiTestContext c = With.A<Window> (80, 25, d)
  243. .Then (
  244. () =>
  245. {
  246. var menuBar = new MenuBarv2 ();
  247. Application.Top!.Add (menuBar);
  248. // Call EnableForDesign
  249. Toplevel top = Application.Top!;
  250. bool result = menuBar.EnableForDesign (ref top);
  251. // Should return true
  252. Assert.True (result);
  253. // Should have created menu items
  254. Assert.True (menuBar.SubViews.Count > 0);
  255. // Should have File, Edit and Help menus
  256. View? fileMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_File");
  257. View? editMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_Edit");
  258. View? helpMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_Help");
  259. Assert.NotNull (fileMenu);
  260. Assert.NotNull (editMenu);
  261. Assert.NotNull (helpMenu);
  262. })
  263. .ScreenShot ("MenuBarv2 EnableForDesign", _out)
  264. .WriteOutLogs (_out)
  265. .Stop ();
  266. }
  267. [Theory]
  268. [ClassData (typeof (V2TestDrivers))]
  269. public void Navigation_Left_Right_Wraps (V2TestDriver d)
  270. {
  271. MenuBarv2? menuBar = null;
  272. using GuiTestContext c = With.A<Window> (50, 20, d)
  273. .Then (
  274. () =>
  275. {
  276. menuBar = new MenuBarv2 ();
  277. Toplevel top = Application.Top!;
  278. menuBar.EnableForDesign (ref top);
  279. Application.Top!.Add (menuBar);
  280. })
  281. .WaitIteration ()
  282. .ScreenShot ("MenuBar initial state", _out)
  283. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  284. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  285. .AssertTrue (menuBar?.IsOpen ())
  286. .AssertEqual ("_New file", Application.Navigation?.GetFocused ()!.Title)
  287. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  288. .Right ()
  289. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  290. .ScreenShot ("After right arrow", _out)
  291. .AssertEqual ("Cu_t", Application.Navigation?.GetFocused ()!.Title)
  292. .Right ()
  293. .ScreenShot ("After second right arrow", _out)
  294. .AssertEqual ("_Online Help...", Application.Navigation?.GetFocused ()!.Title)
  295. .ScreenShot ("After third right arrow", _out)
  296. .Right ()
  297. .ScreenShot ("After fourth right arrow", _out)
  298. .AssertEqual ("_New file", Application.Navigation?.GetFocused ()!.Title)
  299. .Left ()
  300. .ScreenShot ("After left arrow", _out)
  301. .AssertEqual ("_Online Help...", Application.Navigation?.GetFocused ()!.Title)
  302. .WriteOutLogs (_out)
  303. .Stop ();
  304. }
  305. [Theory]
  306. [ClassData (typeof (V2TestDrivers))]
  307. public void MenuBarItem_With_QuitKey_Open_QuitKey_Restores_Focus_Correctly (V2TestDriver d)
  308. {
  309. MenuBarv2? menuBar = null;
  310. using GuiTestContext c = With.A<Window> (50, 20, d)
  311. .Then (
  312. () =>
  313. {
  314. menuBar = new MenuBarv2 ();
  315. Toplevel top = Application.Top!;
  316. top.Add (
  317. new View ()
  318. {
  319. CanFocus = true,
  320. Id = "focusableView",
  321. });
  322. menuBar.EnableForDesign (ref top);
  323. Application.Top!.Add (menuBar);
  324. })
  325. .WaitIteration ()
  326. .AssertIsNotType<MenuItemv2>(Application.Navigation!.GetFocused())
  327. .ScreenShot ("MenuBar initial state", _out)
  328. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  329. .AssertEqual ("_New file", Application.Navigation!.GetFocused ()!.Title)
  330. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  331. .AssertTrue (menuBar?.IsOpen ())
  332. .AssertEqual ("_New file", Application.Navigation?.GetFocused ()!.Title)
  333. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  334. .RaiseKeyDownEvent (Application.QuitKey)
  335. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  336. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  337. .WriteOutLogs (_out)
  338. .Stop ();
  339. }
  340. [Theory]
  341. [ClassData (typeof (V2TestDrivers))]
  342. public void MenuBarItem_Without_QuitKey_Open_QuitKey_Restores_Focus_Correctly (V2TestDriver d)
  343. {
  344. MenuBarv2? menuBar = null;
  345. using GuiTestContext c = With.A<Window> (50, 20, d)
  346. .Then (
  347. () =>
  348. {
  349. menuBar = new MenuBarv2 ();
  350. Toplevel top = Application.Top!;
  351. top.Add (
  352. new View ()
  353. {
  354. CanFocus = true,
  355. Id = "focusableView",
  356. });
  357. menuBar.EnableForDesign (ref top);
  358. Application.Top!.Add (menuBar);
  359. })
  360. .WaitIteration ()
  361. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  362. .ScreenShot ("MenuBar initial state", _out)
  363. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  364. .RaiseKeyDownEvent (Key.CursorRight)
  365. .AssertEqual ("Cu_t", Application.Navigation!.GetFocused ()!.Title)
  366. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  367. .AssertTrue (menuBar?.IsOpen ())
  368. .AssertEqual ("Cu_t", Application.Navigation?.GetFocused ()!.Title)
  369. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  370. .RaiseKeyDownEvent (Application.QuitKey)
  371. .WriteOutLogs (_out)
  372. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  373. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  374. .Stop ();
  375. }
  376. [Theory]
  377. [ClassData (typeof (V2TestDrivers))]
  378. public void MenuBarItem_With_QuitKey_Open_QuitKey_Does_Not_Quit_App (V2TestDriver d)
  379. {
  380. MenuBarv2? menuBar = null;
  381. using GuiTestContext c = With.A<Window> (50, 20, d)
  382. .Then (
  383. () =>
  384. {
  385. menuBar = new MenuBarv2 ();
  386. Toplevel top = Application.Top!;
  387. top.Add (
  388. new View ()
  389. {
  390. CanFocus = true,
  391. Id = "focusableView",
  392. });
  393. menuBar.EnableForDesign (ref top);
  394. Application.Top!.Add (menuBar);
  395. })
  396. .WaitIteration ()
  397. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  398. .ScreenShot ("MenuBar initial state", _out)
  399. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  400. .AssertEqual ("_New file", Application.Navigation!.GetFocused ()!.Title)
  401. .AssertTrue (Application.Top!.Running)
  402. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  403. .RaiseKeyDownEvent (Application.QuitKey)
  404. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  405. .AssertTrue (Application.Top!.Running)
  406. .WriteOutLogs (_out)
  407. .Stop ();
  408. }
  409. [Theory]
  410. [ClassData (typeof (V2TestDrivers))]
  411. public void MenuBarItem_Without_QuitKey_Open_QuitKey_Does_Not_Quit_MenuBar_SuperView (V2TestDriver d)
  412. {
  413. MenuBarv2? menuBar = null;
  414. using GuiTestContext c = With.A<Window> (50, 20, d)
  415. .Then (
  416. () =>
  417. {
  418. menuBar = new MenuBarv2 ();
  419. Toplevel top = Application.Top!;
  420. top.Add (
  421. new View ()
  422. {
  423. CanFocus = true,
  424. Id = "focusableView",
  425. });
  426. menuBar.EnableForDesign (ref top);
  427. IEnumerable<MenuItemv2> items = menuBar.GetMenuItemsWithTitle ("_Quit");
  428. foreach (MenuItemv2 item in items)
  429. {
  430. item.Key = Key.Empty;
  431. }
  432. Application.Top!.Add (menuBar);
  433. })
  434. .WaitIteration ()
  435. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  436. .ScreenShot ("MenuBar initial state", _out)
  437. .RaiseKeyDownEvent (MenuBarv2.DefaultKey)
  438. .AssertEqual ("_New file", Application.Navigation!.GetFocused ()!.Title)
  439. .ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
  440. .RaiseKeyDownEvent (Application.QuitKey)
  441. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  442. .AssertTrue (Application.Top!.Running)
  443. .WriteOutLogs (_out)
  444. .Stop ();
  445. }
  446. [Theory]
  447. [ClassData (typeof (V2TestDrivers))]
  448. public void MenuBar_Not_Active_DoesNotEat_Space (V2TestDriver d)
  449. {
  450. int spaceKeyDownCount = 0;
  451. View testView = new View ()
  452. {
  453. CanFocus = true,
  454. Id = "testView",
  455. };
  456. testView.KeyDown += (sender, key) =>
  457. {
  458. if (key == Key.Space)
  459. {
  460. spaceKeyDownCount++;
  461. }
  462. };
  463. using GuiTestContext c = With.A<Window> (50, 20, d)
  464. .Then (
  465. () =>
  466. {
  467. var menuBar = new MenuBarv2 ();
  468. Toplevel top = Application.Top!;
  469. menuBar.EnableForDesign (ref top);
  470. Application.Top!.Add (menuBar);
  471. })
  472. .Add (testView)
  473. .WaitIteration ()
  474. .Focus (testView)
  475. .RaiseKeyDownEvent (Key.Space)
  476. .AssertEqual (1, spaceKeyDownCount)
  477. .WriteOutLogs (_out)
  478. .Stop ();
  479. }
  480. [Theory]
  481. [ClassData (typeof (V2TestDrivers))]
  482. public void MenuBar_Not_Active_DoesNotEat_Enter (V2TestDriver d)
  483. {
  484. int enterKeyDownCount = 0;
  485. View testView = new View ()
  486. {
  487. CanFocus = true,
  488. Id = "testView",
  489. };
  490. testView.KeyDown += (sender, key) =>
  491. {
  492. if (key == Key.Enter)
  493. {
  494. enterKeyDownCount++;
  495. }
  496. };
  497. using GuiTestContext c = With.A<Window> (50, 20, d)
  498. .Then (
  499. () =>
  500. {
  501. var menuBar = new MenuBarv2 ();
  502. Toplevel top = Application.Top!;
  503. menuBar.EnableForDesign (ref top);
  504. Application.Top!.Add (menuBar);
  505. })
  506. .Add (testView)
  507. .WaitIteration ()
  508. .Focus (testView)
  509. .RaiseKeyDownEvent (Key.Enter)
  510. .AssertEqual (1, enterKeyDownCount)
  511. .WriteOutLogs (_out)
  512. .Stop ();
  513. }
  514. }