ApplicationPopoverTests.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #nullable enable
  2. namespace UnitTests.ApplicationTests;
  3. public class ApplicationPopoverTests
  4. {
  5. [Fact]
  6. public void Application_Init_Initializes_PopoverManager ()
  7. {
  8. // Arrange
  9. Assert.Null (Application.Popover);
  10. Application.Init (new FakeDriver ());
  11. // Act
  12. Assert.NotNull (Application.Popover);
  13. Application.ResetState (true);
  14. }
  15. [Fact]
  16. public void Application_Shutdown_Resets_PopoverManager ()
  17. {
  18. Application.ResetState (true);
  19. // Arrange
  20. Assert.Null (Application.Popover);
  21. Application.Init (new FakeDriver ());
  22. // Act
  23. Assert.NotNull (Application.Popover);
  24. Application.Shutdown ();
  25. // Test
  26. Assert.Null (Application.Popover);
  27. }
  28. [Fact]
  29. public void Application_End_Does_Not_Reset_PopoverManager ()
  30. {
  31. Application.ResetState (true);
  32. // Arrange
  33. Assert.Null (Application.Popover);
  34. Application.Init (new FakeDriver ());
  35. Assert.NotNull (Application.Popover);
  36. Application.Iteration += (s, a) => Application.RequestStop ();
  37. var top = new Toplevel ();
  38. RunState rs = Application.Begin (top);
  39. // Act
  40. Application.End (rs);
  41. // Test
  42. Assert.NotNull (Application.Popover);
  43. top.Dispose ();
  44. Application.Shutdown ();
  45. }
  46. [Fact]
  47. public void Application_End_Hides_Active ()
  48. {
  49. Application.ResetState (true);
  50. // Arrange
  51. Assert.Null (Application.Popover);
  52. Application.Init (new FakeDriver ());
  53. Application.Iteration += (s, a) => Application.RequestStop ();
  54. var top = new Toplevel ();
  55. RunState rs = Application.Begin (top);
  56. PopoverTestClass popover = new ();
  57. Application.Popover?.Show (popover);
  58. Assert.True (popover.Visible);
  59. // Act
  60. Application.End (rs);
  61. top.Dispose ();
  62. // Test
  63. Assert.False (popover.Visible);
  64. Assert.NotNull (Application.Popover);
  65. Application.Shutdown ();
  66. Assert.Equal (1, popover.DisposedCount);
  67. }
  68. [Fact]
  69. public void Application_Shutdown_Disposes_Registered_Popovers ()
  70. {
  71. Application.ResetState (true);
  72. // Arrange
  73. Assert.Null (Application.Popover);
  74. Application.Init (new FakeDriver ());
  75. PopoverTestClass popover = new ();
  76. // Act
  77. Application.Popover?.Register (popover);
  78. Application.Shutdown ();
  79. // Test
  80. Assert.Equal (1, popover.DisposedCount);
  81. }
  82. [Fact]
  83. public void Application_Shutdown_Does_Not_Dispose_DeRegistered_Popovers ()
  84. {
  85. Application.ResetState (true);
  86. // Arrange
  87. Assert.Null (Application.Popover);
  88. Application.Init (new FakeDriver ());
  89. PopoverTestClass popover = new ();
  90. Application.Popover?.Register (popover);
  91. // Act
  92. Application.Popover?.DeRegister (popover);
  93. Application.Shutdown ();
  94. // Test
  95. Assert.Equal (0, popover.DisposedCount);
  96. popover.Dispose ();
  97. Assert.Equal (1, popover.DisposedCount);
  98. }
  99. [Fact]
  100. public void Application_Shutdown_Does_Not_Dispose_ActiveNotRegistered_Popover ()
  101. {
  102. Application.ResetState (true);
  103. // Arrange
  104. Assert.Null (Application.Popover);
  105. Application.Init (new FakeDriver ());
  106. PopoverTestClass popover = new ();
  107. Application.Popover?.Show (popover);
  108. Application.Popover?.DeRegister (popover);
  109. // Act
  110. Application.Shutdown ();
  111. // Test
  112. Assert.Equal (0, popover.DisposedCount);
  113. popover.Dispose ();
  114. Assert.Equal (1, popover.DisposedCount);
  115. }
  116. [Fact]
  117. public void Register_SetsTopLevel ()
  118. {
  119. Application.ResetState (true);
  120. // Arrange
  121. Assert.Null (Application.Popover);
  122. Application.Init (new FakeDriver ());
  123. Application.Top = new Toplevel ();
  124. PopoverTestClass popover = new ();
  125. // Act
  126. Application.Popover?.Register (popover);
  127. // Assert
  128. Assert.Equal (Application.Top, popover.Toplevel);
  129. Application.ResetState (true);
  130. }
  131. [Fact]
  132. public void Keyboard_Events_Go_Only_To_Popover_Associated_With_Toplevel ()
  133. {
  134. Application.ResetState (true);
  135. // Arrange
  136. Assert.Null (Application.Popover);
  137. Application.Init (new FakeDriver ());
  138. Application.Top = new Toplevel () { Id = "initialTop" };
  139. PopoverTestClass popover = new ();
  140. int keyDownEvents = 0;
  141. popover.KeyDown += (s, e) =>
  142. {
  143. keyDownEvents++;
  144. e.Handled = true;
  145. }; // Ensure it handles the key
  146. Application.Popover?.Register (popover);
  147. // Act
  148. Application.RaiseKeyDownEvent (Key.A); // Goes to initialTop
  149. Application.Top = new Toplevel () { Id = "secondaryTop" };
  150. Application.RaiseKeyDownEvent (Key.A); // Goes to secondaryTop
  151. // Test
  152. Assert.Equal (1, keyDownEvents);
  153. popover.Dispose ();
  154. Assert.Equal (1, popover.DisposedCount);
  155. Application.ResetState (true);
  156. }
  157. // See: https://github.com/gui-cs/Terminal.Gui/issues/4122
  158. [Theory]
  159. [InlineData (0, 0, new [] { "top" })]
  160. [InlineData (10, 10, new string [] { })]
  161. [InlineData (1, 1, new [] { "top", "view" })]
  162. [InlineData (5, 5, new [] { "top" })]
  163. [InlineData (6, 6, new [] { "popoverSubView" })]
  164. [InlineData (7, 7, new [] { "top" })]
  165. [InlineData (3, 3, new [] { "top" })]
  166. public void GetViewsUnderMouse_Supports_ActivePopover (int mouseX, int mouseY, string [] viewIdStrings)
  167. {
  168. Application.ResetState (true);
  169. // Arrange
  170. Assert.Null (Application.Popover);
  171. Application.Init (new FakeDriver ());
  172. Application.Top = new ()
  173. {
  174. Frame = new (0, 0, 10, 10),
  175. Id = "top"
  176. };
  177. View view = new ()
  178. {
  179. Id = "view",
  180. X = 1,
  181. Y = 1,
  182. Width = 2,
  183. Height = 2,
  184. }; // at 1,1 to 3,2 (screen)
  185. Application.Top.Add (view);
  186. PopoverTestClass popover = new ()
  187. {
  188. Id = "popover",
  189. X = 5,
  190. Y = 5,
  191. Width = 3,
  192. Height = 3,
  193. }; // at 5,5 to 8,8 (screen)
  194. View popoverSubView = new ()
  195. {
  196. Id = "popoverSubView",
  197. X = 1,
  198. Y = 1,
  199. Width = 1,
  200. Height = 1,
  201. }; // at 6,6 to 7,7 (screen)
  202. popover.Add (popoverSubView);
  203. Application.Popover?.Show (popover);
  204. List<View?> found = View.GetViewsUnderLocation (new (mouseX, mouseY), ViewportSettingsFlags.TransparentMouse);
  205. string [] foundIds = found.Select (v => v!.Id).ToArray ();
  206. Assert.Equal (viewIdStrings, foundIds);
  207. popover.Dispose ();
  208. Application.Top.Dispose ();
  209. Application.ResetState (true);
  210. }
  211. public class PopoverTestClass : PopoverBaseImpl
  212. {
  213. public List<Key> HandledKeys { get; } = [];
  214. public int NewCommandInvokeCount { get; private set; }
  215. // NOTE: Hides the base DisposedCount property
  216. public new int DisposedCount { get; private set; }
  217. public PopoverTestClass ()
  218. {
  219. CanFocus = true;
  220. AddCommand (Command.New, NewCommandHandler!);
  221. HotKeyBindings.Add (Key.N.WithCtrl, Command.New);
  222. return;
  223. bool? NewCommandHandler (ICommandContext ctx)
  224. {
  225. NewCommandInvokeCount++;
  226. return false;
  227. }
  228. }
  229. protected override bool OnKeyDown (Key key)
  230. {
  231. HandledKeys.Add (key);
  232. return false;
  233. }
  234. /// <inheritdoc/>
  235. protected override void Dispose (bool disposing)
  236. {
  237. base.Dispose (disposing);
  238. DisposedCount++;
  239. }
  240. }
  241. }