MenuBarv2Tests.cs 29 KB

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