PopverMenuTests.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. using System.Globalization;
  2. using TerminalGuiFluentTesting;
  3. using TerminalGuiFluentTestingXunit;
  4. using Xunit.Abstractions;
  5. namespace IntegrationTests.FluentTests;
  6. /// <summary>
  7. /// Tests for the PopoverMenu class
  8. /// </summary>
  9. public class PopoverMenuTests
  10. {
  11. private readonly TextWriter _out;
  12. public PopoverMenuTests (ITestOutputHelper outputHelper)
  13. {
  14. CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
  15. _out = new TestOutputWriter (outputHelper);
  16. }
  17. [Theory]
  18. [ClassData (typeof (TestDrivers))]
  19. public void EnableForDesign_CreatesMenuItems (TestDriver d)
  20. {
  21. using GuiTestContext c = With.A<Window> (80, 25, d)
  22. .Then (() =>
  23. {
  24. PopoverMenu popoverMenu = new ();
  25. Application.Top!.Add (popoverMenu);
  26. // Call EnableForDesign
  27. Toplevel top = Application.Top;
  28. bool result = popoverMenu.EnableForDesign (ref top);
  29. // Should return true
  30. Assert.True (result);
  31. // Should have created menu items
  32. Assert.NotNull (popoverMenu.Root);
  33. Assert.Equal (7, popoverMenu.Root.SubViews.Count);
  34. // Should have Cut menu item
  35. View? cutMenuItem = popoverMenu.GetMenuItemsOfAllSubMenus ().FirstOrDefault (v => v?.Title == "Cu_t");
  36. Assert.NotNull (cutMenuItem);
  37. });
  38. }
  39. private static readonly object o = new ();
  40. [Theory]
  41. [ClassData (typeof (TestDrivers))]
  42. public void Activate_Sets_Application_Navigation_Correctly (TestDriver d)
  43. {
  44. lock (o)
  45. {
  46. using GuiTestContext c = With.A<Window> (50, 20, d)
  47. .Then (() =>
  48. {
  49. PopoverMenu popoverMenu = new ();
  50. // Call EnableForDesign
  51. Toplevel top = Application.Top!;
  52. popoverMenu.EnableForDesign (ref top);
  53. var view = new View
  54. {
  55. CanFocus = true,
  56. Height = Dim.Auto (),
  57. Width = Dim.Auto (),
  58. Id = "focusableView",
  59. Text = "View"
  60. };
  61. Application.Top!.Add (view);
  62. // EnableForDesign sets to true; undo that
  63. popoverMenu.Visible = false;
  64. Application.Popover!.Register (popoverMenu);
  65. view.SetFocus ();
  66. })
  67. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  68. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  69. .ScreenShot ("PopoverMenu initial state", _out)
  70. .Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
  71. .ScreenShot ("After Show", _out)
  72. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  73. .AssertEqual ("Cu_t", Application.Navigation!.GetFocused ()!.Title);
  74. }
  75. }
  76. [Theory]
  77. [ClassData (typeof (TestDrivers))]
  78. public void QuitKey_Hides (TestDriver d)
  79. {
  80. using GuiTestContext c = With.A<Window> (50, 20, d)
  81. .Then (() =>
  82. {
  83. PopoverMenu popoverMenu = new ();
  84. // Call EnableForDesign
  85. Toplevel top = Application.Top!;
  86. bool result = popoverMenu.EnableForDesign (ref top);
  87. var view = new View
  88. {
  89. CanFocus = true,
  90. Height = Dim.Auto (),
  91. Width = Dim.Auto (),
  92. Id = "focusableView",
  93. Text = "View"
  94. };
  95. Application.Top!.Add (view);
  96. // EnableForDesign sets to true; undo that
  97. popoverMenu.Visible = false;
  98. Application.Popover!.Register (popoverMenu);
  99. view.SetFocus ();
  100. })
  101. .ScreenShot ("PopoverMenu initial state", _out)
  102. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  103. .Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
  104. .ScreenShot ("After Show", _out)
  105. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  106. .EnqueueKeyEvent (Application.QuitKey)
  107. .ScreenShot ($"After {Application.QuitKey}", _out)
  108. .AssertFalse (Application.Popover!.Popovers.Cast<PopoverMenu> ().FirstOrDefault ()!.Visible)
  109. .AssertNull (Application.Popover!.GetActivePopover ())
  110. .AssertTrue (Application.Top!.Running);
  111. }
  112. [Theory]
  113. [ClassData (typeof (TestDrivers))]
  114. public void QuitKey_Restores_Focus_Correctly (TestDriver d)
  115. {
  116. using GuiTestContext c = With.A<Window> (50, 20, d)
  117. .Then (() =>
  118. {
  119. PopoverMenu popoverMenu = new ();
  120. // Call EnableForDesign
  121. Toplevel top = Application.Top!;
  122. bool result = popoverMenu.EnableForDesign (ref top);
  123. var view = new View
  124. {
  125. CanFocus = true,
  126. Height = Dim.Auto (),
  127. Width = Dim.Auto (),
  128. Id = "focusableView",
  129. Text = "View"
  130. };
  131. Application.Top!.Add (view);
  132. // EnableForDesign sets to true; undo that
  133. popoverMenu.Visible = false;
  134. Application.Popover!.Register (popoverMenu);
  135. view.SetFocus ();
  136. })
  137. .ScreenShot ("PopoverMenu initial state", _out)
  138. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  139. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  140. .Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
  141. .ScreenShot ("After Show", _out)
  142. .AssertTrue (Application.Popover?.GetActivePopover () is PopoverMenu)
  143. .AssertIsType<MenuItemv2> (Application.Navigation!.GetFocused ())
  144. .EnqueueKeyEvent (Application.QuitKey)
  145. .ScreenShot ($"After {Application.QuitKey}", _out)
  146. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  147. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ());
  148. }
  149. [Theory]
  150. [ClassData (typeof (TestDrivers))]
  151. public void MenuBarItem_With_QuitKey_Open_QuitKey_Does_Not_Quit_App (TestDriver d)
  152. {
  153. using GuiTestContext c = With.A<Window> (50, 20, d)
  154. .Then (() =>
  155. {
  156. PopoverMenu popoverMenu = new ();
  157. // Call EnableForDesign
  158. Toplevel top = Application.Top!;
  159. bool result = popoverMenu.EnableForDesign (ref top);
  160. var view = new View
  161. {
  162. CanFocus = true,
  163. Height = Dim.Auto (),
  164. Width = Dim.Auto (),
  165. Id = "focusableView",
  166. Text = "View"
  167. };
  168. Application.Top!.Add (view);
  169. // EnableForDesign sets to true; undo that
  170. popoverMenu.Visible = false;
  171. Application.Popover!.Register (popoverMenu);
  172. view.SetFocus ();
  173. })
  174. .AssertIsNotType<MenuItemv2> (Application.Navigation!.GetFocused ())
  175. .ScreenShot ("PopoverMenu initial state", _out)
  176. .Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
  177. .ScreenShot ("PopoverMenu after Show", _out)
  178. .AssertEqual ("Cu_t", Application.Navigation!.GetFocused ()!.Title)
  179. .AssertTrue (Application.Top!.Running)
  180. .EnqueueKeyEvent (Application.QuitKey)
  181. .ScreenShot ($"After {Application.QuitKey}", _out)
  182. .AssertFalse (Application.Popover?.GetActivePopover () is PopoverMenu)
  183. .AssertTrue (Application.Top!.Running);
  184. }
  185. [Theory]
  186. [ClassData (typeof (TestDrivers))]
  187. public void Not_Active_DoesNotEat_Space (TestDriver d)
  188. {
  189. var spaceKeyDownCount = 0;
  190. var testView = new View
  191. {
  192. CanFocus = true,
  193. Id = "testView"
  194. };
  195. testView.KeyDown += (sender, key) =>
  196. {
  197. if (key == Key.Space)
  198. {
  199. spaceKeyDownCount++;
  200. }
  201. };
  202. using GuiTestContext c = With.A<Window> (50, 20, d)
  203. .Then (() =>
  204. {
  205. PopoverMenu popoverMenu = new ();
  206. Toplevel top = Application.Top!;
  207. popoverMenu.EnableForDesign (ref top);
  208. Application.Popover!.Register (popoverMenu);
  209. })
  210. .Add (testView)
  211. .Focus (testView)
  212. .EnqueueKeyEvent (Key.Space)
  213. .AssertEqual (1, spaceKeyDownCount);
  214. }
  215. [Theory]
  216. [ClassData (typeof (TestDrivers))]
  217. public void Not_Active_DoesNotEat_Enter (TestDriver d)
  218. {
  219. var enterKeyDownCount = 0;
  220. var testView = new View
  221. {
  222. CanFocus = true,
  223. Id = "testView"
  224. };
  225. testView.KeyDown += (sender, key) =>
  226. {
  227. if (key == Key.Enter)
  228. {
  229. enterKeyDownCount++;
  230. }
  231. };
  232. using GuiTestContext c = With.A<Window> (50, 20, d)
  233. .Then (() =>
  234. {
  235. PopoverMenu popoverMenu = new ();
  236. Toplevel top = Application.Top!;
  237. popoverMenu.EnableForDesign (ref top);
  238. Application.Popover!.Register (popoverMenu);
  239. })
  240. .Add (testView)
  241. .Focus (testView)
  242. .EnqueueKeyEvent (Key.Enter)
  243. .AssertEqual (1, enterKeyDownCount);
  244. }
  245. [Theory]
  246. [ClassData (typeof (TestDrivers))]
  247. public void Not_Active_DoesNotEat_QuitKey (TestDriver d)
  248. {
  249. var quitKeyDownCount = 0;
  250. var testView = new View
  251. {
  252. CanFocus = true,
  253. Id = "testView"
  254. };
  255. testView.KeyDown += (sender, key) =>
  256. {
  257. if (key == Application.QuitKey)
  258. {
  259. quitKeyDownCount++;
  260. }
  261. };
  262. using GuiTestContext c = With.A<Window> (50, 20, d)
  263. .Then (() =>
  264. {
  265. PopoverMenu popoverMenu = new ();
  266. Toplevel top = Application.Top!;
  267. popoverMenu.EnableForDesign (ref top);
  268. Application.Popover!.Register (popoverMenu);
  269. })
  270. .Add (testView)
  271. .EnqueueKeyEvent (Application.QuitKey)
  272. .AssertEqual (1, quitKeyDownCount);
  273. }
  274. [Theory]
  275. [ClassData (typeof (TestDrivers))]
  276. public void ContextMenu_CrashesOnRight (TestDriver d)
  277. {
  278. var clicked = false;
  279. MenuItemv2 [] menuItems = [new ("_New File", string.Empty, () => { clicked = true; })];
  280. using GuiTestContext c = With.A<Window> (40, 10, d, _out)
  281. .WithContextMenu (new (menuItems))
  282. .ScreenShot ("Before open menu", _out)
  283. // Click in main area inside border
  284. .RightClick (1, 1)
  285. .Then (() =>
  286. {
  287. // Test depends on menu having a border
  288. IPopover? popover = Application.Popover!.GetActivePopover ();
  289. Assert.NotNull (popover);
  290. var popoverMenu = popover as PopoverMenu;
  291. popoverMenu!.Root!.BorderStyle = LineStyle.Single;
  292. })
  293. .ScreenShot ("After open menu", _out)
  294. .LeftClick (2, 2)
  295. ;
  296. Assert.True (clicked);
  297. }
  298. [Theory]
  299. [ClassData (typeof (TestDrivers))]
  300. public void ContextMenu_OpenSubmenu (TestDriver d)
  301. {
  302. var clicked = false;
  303. MenuItemv2 [] menuItems =
  304. [
  305. new ("One", "", null),
  306. new ("Two", "", null),
  307. new ("Three", "", null),
  308. new (
  309. "Four",
  310. "",
  311. new (
  312. [
  313. new ("SubMenu1", "", null),
  314. new ("SubMenu2", "", () => clicked = true),
  315. new ("SubMenu3", "", null),
  316. new ("SubMenu4", "", null),
  317. new ("SubMenu5", "", null),
  318. new ("SubMenu6", "", null),
  319. new ("SubMenu7", "", null)
  320. ])),
  321. new ("Five", "", null),
  322. new ("Six", "", null)
  323. ];
  324. using GuiTestContext c = With.A<Window> (40, 10, d)
  325. .WithContextMenu (new (menuItems))
  326. .ScreenShot ("Before open menu", _out)
  327. // Click in main area inside border
  328. .RightClick (1, 1)
  329. .ScreenShot ("After open menu", _out)
  330. .EnqueueKeyEvent (Key.CursorDown)
  331. .EnqueueKeyEvent (Key.CursorDown)
  332. .EnqueueKeyEvent (Key.CursorDown)
  333. .EnqueueKeyEvent (Key.CursorRight)
  334. .ScreenShot ("After open submenu", _out)
  335. .EnqueueKeyEvent (Key.CursorDown)
  336. .EnqueueKeyEvent (Key.Enter)
  337. .ScreenShot ("Menu should be closed after selecting", _out);
  338. Assert.True (clicked);
  339. }
  340. }