ResponderTests.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. // Alias Console to MockConsole so we don't accidentally use Console
  2. namespace Terminal.Gui.InputTests;
  3. public class ResponderTests
  4. {
  5. // Generic lifetime (IDisposable) tests
  6. [Fact]
  7. [TestRespondersDisposed]
  8. public void Dispose_Works ()
  9. {
  10. var r = new Responder ();
  11. #if DEBUG_IDISPOSABLE
  12. Assert.Single (Responder.Instances);
  13. #endif
  14. r.Dispose ();
  15. #if DEBUG_IDISPOSABLE
  16. Assert.Empty (Responder.Instances);
  17. #endif
  18. }
  19. [Fact]
  20. public void Disposing_Event_Notify_All_Subscribers_On_The_First_Container ()
  21. {
  22. #if DEBUG_IDISPOSABLE
  23. // Only clear before because need to test after assert
  24. Responder.Instances.Clear ();
  25. #endif
  26. var container1 = new View { Id = "Container1" };
  27. var count = 0;
  28. var view = new View { Id = "View" };
  29. view.Disposing += View_Disposing;
  30. container1.Add (view);
  31. Assert.Equal (container1, view.SuperView);
  32. void View_Disposing (object sender, EventArgs e)
  33. {
  34. count++;
  35. Assert.Equal (view, sender);
  36. container1.Remove ((View)sender);
  37. }
  38. Assert.Single (container1.Subviews);
  39. var container2 = new View { Id = "Container2" };
  40. container2.Add (view);
  41. Assert.Equal (container2, view.SuperView);
  42. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  43. container2.Dispose ();
  44. Assert.Empty (container1.Subviews);
  45. Assert.Empty (container2.Subviews);
  46. Assert.Equal (1, count);
  47. Assert.Null (view.SuperView);
  48. container1.Dispose ();
  49. #if DEBUG_IDISPOSABLE
  50. Assert.Empty (Responder.Instances);
  51. #endif
  52. }
  53. [Fact]
  54. public void Disposing_Event_Notify_All_Subscribers_On_The_Second_Container ()
  55. {
  56. #if DEBUG_IDISPOSABLE
  57. // Only clear before because need to test after assert
  58. Responder.Instances.Clear ();
  59. #endif
  60. var container1 = new View { Id = "Container1" };
  61. var view = new View { Id = "View" };
  62. container1.Add (view);
  63. Assert.Equal (container1, view.SuperView);
  64. Assert.Single (container1.Subviews);
  65. var container2 = new View { Id = "Container2" };
  66. var count = 0;
  67. view.Disposing += View_Disposing;
  68. container2.Add (view);
  69. Assert.Equal (container2, view.SuperView);
  70. void View_Disposing (object sender, EventArgs e)
  71. {
  72. count++;
  73. Assert.Equal (view, sender);
  74. container2.Remove ((View)sender);
  75. }
  76. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  77. container1.Dispose ();
  78. Assert.Empty (container1.Subviews);
  79. Assert.Empty (container2.Subviews);
  80. Assert.Equal (1, count);
  81. Assert.Null (view.SuperView);
  82. container2.Dispose ();
  83. #if DEBUG_IDISPOSABLE
  84. Assert.Empty (Responder.Instances);
  85. #endif
  86. }
  87. [Fact]
  88. [TestRespondersDisposed]
  89. public void IsOverridden_False_IfNotOverridden ()
  90. {
  91. // MouseEvent IS defined on Responder but NOT overridden
  92. Assert.False (Responder.IsOverridden (new Responder (), "MouseEvent"));
  93. // MouseEvent is defined on Responder and NOT overrident on View
  94. Assert.False (
  95. Responder.IsOverridden (
  96. new View { Text = "View does not override MouseEvent" },
  97. "MouseEvent"
  98. )
  99. );
  100. Assert.False (
  101. Responder.IsOverridden (
  102. new DerivedView { Text = "DerivedView does not override MouseEvent" },
  103. "MouseEvent"
  104. )
  105. );
  106. // MouseEvent is NOT defined on DerivedView
  107. Assert.False (
  108. Responder.IsOverridden (
  109. new DerivedView { Text = "DerivedView does not override MouseEvent" },
  110. "MouseEvent"
  111. )
  112. );
  113. // OnKeyDown is defined on View and NOT overrident on Button
  114. Assert.False (
  115. Responder.IsOverridden (
  116. new Button { Text = "Button does not override OnKeyDown" },
  117. "OnKeyDown"
  118. )
  119. );
  120. #if DEBUG_IDISPOSABLE
  121. // HACK: Force clean up of Responders to avoid having to Dispose all the Views created above.
  122. Responder.Instances.Clear ();
  123. Assert.Empty (Responder.Instances);
  124. #endif
  125. }
  126. [Fact]
  127. [TestRespondersDisposed]
  128. public void IsOverridden_True_IfOverridden ()
  129. {
  130. // MouseEvent is defined on Responder IS overriden on ScrollBarView (but not View)
  131. Assert.True (
  132. Responder.IsOverridden (
  133. new ScrollBarView { Text = "ScrollBarView overrides MouseEvent" },
  134. "MouseEvent"
  135. )
  136. );
  137. // OnKeyDown is defined on View
  138. Assert.False (Responder.IsOverridden (new View { Text = "View overrides OnKeyDown" }, "OnKeyDown"));
  139. // OnKeyDown is defined on DerivedView
  140. Assert.True (
  141. Responder.IsOverridden (
  142. new DerivedView { Text = "DerivedView overrides OnKeyDown" },
  143. "OnKeyDown"
  144. )
  145. );
  146. // ScrollBarView overrides both MouseEvent (from Responder) and Redraw (from View)
  147. Assert.True (
  148. Responder.IsOverridden (
  149. new ScrollBarView { Text = "ScrollBarView overrides MouseEvent" },
  150. "MouseEvent"
  151. )
  152. );
  153. Assert.True (
  154. Responder.IsOverridden (
  155. new ScrollBarView { Text = "ScrollBarView overrides OnDrawContent" },
  156. "OnDrawContent"
  157. )
  158. );
  159. Assert.True (
  160. Responder.IsOverridden (
  161. new Button { Text = "Button overrides MouseEvent" },
  162. "MouseEvent"
  163. )
  164. );
  165. #if DEBUG_IDISPOSABLE
  166. // HACK: Force clean up of Responders to avoid having to Dispose all the Views created above.
  167. Responder.Instances.Clear ();
  168. Assert.Empty (Responder.Instances);
  169. #endif
  170. }
  171. [Fact]
  172. public void KeyPressed_Handled_True_Cancels_KeyPress ()
  173. {
  174. var r = new View ();
  175. var args = new Key { KeyCode = KeyCode.Null };
  176. Assert.False (r.OnKeyDown (args));
  177. Assert.False (args.Handled);
  178. r.KeyDown += (s, a) => a.Handled = true;
  179. Assert.True (r.OnKeyDown (args));
  180. Assert.True (args.Handled);
  181. r.Dispose ();
  182. }
  183. [Fact]
  184. [TestRespondersDisposed]
  185. public void New_Initializes ()
  186. {
  187. var r = new Responder ();
  188. Assert.NotNull (r);
  189. Assert.Equal ("Terminal.Gui.Responder", r.ToString ());
  190. Assert.False (r.CanFocus);
  191. Assert.False (r.HasFocus);
  192. Assert.True (r.Enabled);
  193. Assert.True (r.Visible);
  194. r.Dispose ();
  195. }
  196. [Fact]
  197. [TestRespondersDisposed]
  198. public void New_Methods_Return_False ()
  199. {
  200. var r = new View ();
  201. //Assert.False (r.OnKeyDown (new KeyEventArgs () { Key = Key.Unknown }));
  202. Assert.False (r.OnKeyDown (new Key { KeyCode = KeyCode.Null }));
  203. Assert.False (r.OnKeyUp (new Key { KeyCode = KeyCode.Null }));
  204. Assert.False (r.MouseEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
  205. Assert.False (r.OnMouseEnter (new MouseEvent { Flags = MouseFlags.AllEvents }));
  206. Assert.False (r.OnMouseLeave (new MouseEvent { Flags = MouseFlags.AllEvents }));
  207. var v = new View ();
  208. Assert.False (r.OnEnter (v));
  209. v.Dispose ();
  210. v = new View ();
  211. Assert.False (r.OnLeave (v));
  212. v.Dispose ();
  213. r.Dispose ();
  214. }
  215. [Fact]
  216. public void Responder_Not_Notifying_Dispose ()
  217. {
  218. // Only clear before because need to test after assert
  219. #if DEBUG_IDISPOSABLE
  220. Responder.Instances.Clear ();
  221. #endif
  222. var container1 = new View { Id = "Container1" };
  223. var view = new View { Id = "View" };
  224. container1.Add (view);
  225. Assert.Equal (container1, view.SuperView);
  226. Assert.Single (container1.Subviews);
  227. var container2 = new View { Id = "Container2" };
  228. container2.Add (view);
  229. Assert.Equal (container2, view.SuperView);
  230. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  231. container1.Dispose ();
  232. Assert.Empty (container1.Subviews);
  233. Assert.NotEmpty (container2.Subviews);
  234. Assert.Single (container2.Subviews);
  235. Assert.Null (view.SuperView);
  236. // Trying access disposed properties
  237. #if DEBUG_IDISPOSABLE
  238. Assert.True (container2.Subviews [0].WasDisposed);
  239. #endif
  240. Assert.False (container2.Subviews [0].CanFocus);
  241. Assert.Null (container2.Subviews [0].Margin);
  242. Assert.Null (container2.Subviews [0].Border);
  243. Assert.Null (container2.Subviews [0].Padding);
  244. Assert.Null (view.SuperView);
  245. container2.Dispose ();
  246. #if DEBUG_IDISPOSABLE
  247. Assert.Empty (Responder.Instances);
  248. #endif
  249. }
  250. public class DerivedView : View
  251. {
  252. public override bool OnKeyDown (Key keyEvent) { return true; }
  253. }
  254. }