AppendAutocompleteTests.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using UnitTests;
  2. using Xunit.Abstractions;
  3. namespace Terminal.Gui.TextTests;
  4. public class AppendAutocompleteTests (ITestOutputHelper output)
  5. {
  6. [Fact]
  7. [AutoInitShutdown]
  8. public void TestAutoAppend_AfterCloseKey_NoAutocomplete ()
  9. {
  10. TextField tf = GetTextFieldsInViewSuggesting ("fish");
  11. View.SetClipToScreen ();
  12. // f is typed and suggestion is "fish"
  13. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  14. tf.Draw ();
  15. tf.PositionCursor ();
  16. DriverAssert.AssertDriverContentsAre ("fish", output);
  17. Assert.Equal ("f", tf.Text);
  18. // When cancelling autocomplete
  19. Application.Driver?.SendKeys ('e', ConsoleKey.Escape, false, false, false);
  20. // Suggestion should disappear
  21. View.SetClipToScreen ();
  22. tf.Draw ();
  23. DriverAssert.AssertDriverContentsAre ("f", output);
  24. Assert.Equal ("f", tf.Text);
  25. // Still has focus though
  26. Assert.Same (tf, Application.Top.Focused);
  27. // But can tab away
  28. Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
  29. Assert.NotSame (tf, Application.Top.Focused);
  30. Application.Top.Dispose ();
  31. }
  32. [Fact]
  33. [AutoInitShutdown]
  34. public void TestAutoAppend_AfterCloseKey_ReappearsOnLetter ()
  35. {
  36. TextField tf = GetTextFieldsInViewSuggesting ("fish");
  37. // f is typed and suggestion is "fish"
  38. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  39. View.SetClipToScreen ();
  40. tf.Draw ();
  41. tf.PositionCursor ();
  42. DriverAssert.AssertDriverContentsAre ("fish", output);
  43. Assert.Equal ("f", tf.Text);
  44. // When cancelling autocomplete
  45. Application.Driver?.SendKeys ('\0', ConsoleKey.Escape, false, false, false);
  46. // Suggestion should disappear
  47. View.SetClipToScreen ();
  48. tf.Draw ();
  49. DriverAssert.AssertDriverContentsAre ("f", output);
  50. Assert.Equal ("f", tf.Text);
  51. // Should reappear when you press next letter
  52. Application.Driver?.SendKeys ('i', ConsoleKey.I, false, false, false);
  53. tf.PositionCursor ();
  54. View.SetClipToScreen ();
  55. tf.Draw ();
  56. DriverAssert.AssertDriverContentsAre ("fish", output);
  57. Assert.Equal ("fi", tf.Text);
  58. Application.Top.Dispose ();
  59. }
  60. [Theory]
  61. [AutoInitShutdown]
  62. [InlineData (ConsoleKey.UpArrow)]
  63. [InlineData (ConsoleKey.DownArrow)]
  64. public void TestAutoAppend_CycleSelections (ConsoleKey cycleKey)
  65. {
  66. TextField tf = GetTextFieldsInViewSuggesting ("fish", "friend");
  67. // f is typed and suggestion is "fish"
  68. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  69. View.SetClipToScreen ();
  70. tf.Draw ();
  71. tf.PositionCursor ();
  72. DriverAssert.AssertDriverContentsAre ("fish", output);
  73. Assert.Equal ("f", tf.Text);
  74. // When cycling autocomplete
  75. Application.Driver?.SendKeys (' ', cycleKey, false, false, false);
  76. View.SetClipToScreen ();
  77. tf.Draw ();
  78. tf.PositionCursor ();
  79. DriverAssert.AssertDriverContentsAre ("friend", output);
  80. Assert.Equal ("f", tf.Text);
  81. // Should be able to cycle in circles endlessly
  82. Application.Driver?.SendKeys (' ', cycleKey, false, false, false);
  83. View.SetClipToScreen ();
  84. tf.Draw ();
  85. tf.PositionCursor ();
  86. DriverAssert.AssertDriverContentsAre ("fish", output);
  87. Assert.Equal ("f", tf.Text);
  88. Application.Top.Dispose ();
  89. }
  90. [Fact]
  91. [AutoInitShutdown]
  92. public void TestAutoAppend_NoRender_WhenCursorNotAtEnd ()
  93. {
  94. TextField tf = GetTextFieldsInViewSuggesting ("fish");
  95. // f is typed and suggestion is "fish"
  96. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  97. View.SetClipToScreen ();
  98. tf.Draw ();
  99. tf.PositionCursor ();
  100. DriverAssert.AssertDriverContentsAre ("fish", output);
  101. Assert.Equal ("f", tf.Text);
  102. // add a space then go back 1
  103. Application.Driver?.SendKeys (' ', ConsoleKey.Spacebar, false, false, false);
  104. Application.Driver?.SendKeys ('<', ConsoleKey.LeftArrow, false, false, false);
  105. View.SetClipToScreen ();
  106. tf.Draw ();
  107. DriverAssert.AssertDriverContentsAre ("f", output);
  108. Assert.Equal ("f ", tf.Text);
  109. Application.Top.Dispose ();
  110. }
  111. [Fact]
  112. [AutoInitShutdown]
  113. public void TestAutoAppend_NoRender_WhenNoMatch ()
  114. {
  115. TextField tf = GetTextFieldsInViewSuggesting ("fish");
  116. // f is typed and suggestion is "fish"
  117. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  118. View.SetClipToScreen ();
  119. tf.Draw ();
  120. tf.PositionCursor ();
  121. DriverAssert.AssertDriverContentsAre ("fish", output);
  122. Assert.Equal ("f", tf.Text);
  123. // x is typed and suggestion should disappear
  124. Application.Driver?.SendKeys ('x', ConsoleKey.X, false, false, false);
  125. View.SetClipToScreen ();
  126. tf.Draw ();
  127. DriverAssert.AssertDriverContentsAre ("fx", output);
  128. Assert.Equal ("fx", tf.Text);
  129. Application.Top.Dispose ();
  130. }
  131. [Fact]
  132. [AutoInitShutdown]
  133. public void TestAutoAppend_ShowThenAccept_CasesDiffer ()
  134. {
  135. TextField tf = GetTextFieldsInView ();
  136. tf.Autocomplete = new AppendAutocomplete (tf);
  137. var generator = (SingleWordSuggestionGenerator)tf.Autocomplete.SuggestionGenerator;
  138. generator.AllSuggestions = new List<string> { "FISH" };
  139. View.SetClipToScreen ();
  140. tf.Draw ();
  141. tf.PositionCursor ();
  142. DriverAssert.AssertDriverContentsAre ("", output);
  143. tf.NewKeyDownEvent (Key.M);
  144. tf.NewKeyDownEvent (Key.Y);
  145. tf.NewKeyDownEvent (Key.Space);
  146. tf.NewKeyDownEvent (Key.F);
  147. Assert.Equal ("my f", tf.Text);
  148. // Even though there is no match on case we should still get the suggestion
  149. View.SetClipToScreen ();
  150. tf.Draw ();
  151. tf.PositionCursor ();
  152. DriverAssert.AssertDriverContentsAre ("my fISH", output);
  153. Assert.Equal ("my f", tf.Text);
  154. // When tab completing the case of the whole suggestion should be applied
  155. Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
  156. View.SetClipToScreen ();
  157. tf.Draw ();
  158. DriverAssert.AssertDriverContentsAre ("my FISH", output);
  159. Assert.Equal ("my FISH", tf.Text);
  160. Application.Top.Dispose ();
  161. }
  162. [Fact]
  163. [AutoInitShutdown]
  164. public void TestAutoAppend_ShowThenAccept_MatchCase ()
  165. {
  166. TextField tf = GetTextFieldsInView ();
  167. tf.Autocomplete = new AppendAutocomplete (tf);
  168. var generator = (SingleWordSuggestionGenerator)tf.Autocomplete.SuggestionGenerator;
  169. generator.AllSuggestions = new List<string> { "fish" };
  170. View.SetClipToScreen ();
  171. tf.Draw ();
  172. tf.PositionCursor ();
  173. DriverAssert.AssertDriverContentsAre ("", output);
  174. tf.NewKeyDownEvent (new Key ('f'));
  175. View.SetClipToScreen ();
  176. tf.Draw ();
  177. tf.PositionCursor ();
  178. DriverAssert.AssertDriverContentsAre ("fish", output);
  179. Assert.Equal ("f", tf.Text);
  180. Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
  181. View.SetClipToScreen ();
  182. tf.Draw ();
  183. DriverAssert.AssertDriverContentsAre ("fish", output);
  184. Assert.Equal ("fish", tf.Text);
  185. // Tab should autcomplete but not move focus
  186. Assert.Same (tf, Application.Top.Focused);
  187. // Second tab should move focus (nothing to autocomplete)
  188. Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
  189. Assert.NotSame (tf, Application.Top.Focused);
  190. Application.Top.Dispose ();
  191. }
  192. [Theory]
  193. [AutoInitShutdown]
  194. [InlineData ("ffffffffffffffffffffffffff", "ffffffffff")]
  195. [InlineData ("f234567890", "f234567890")]
  196. [InlineData ("fisérables", "fisérables")]
  197. public void TestAutoAppendRendering_ShouldNotOverspill (string overspillUsing, string expectRender)
  198. {
  199. TextField tf = GetTextFieldsInViewSuggesting (overspillUsing);
  200. // f is typed we should only see 'f' up to size of View (10)
  201. Application.Driver?.SendKeys ('f', ConsoleKey.F, false, false, false);
  202. View.SetClipToScreen ();
  203. tf.Draw ();
  204. tf.PositionCursor ();
  205. DriverAssert.AssertDriverContentsAre (expectRender, output);
  206. Assert.Equal ("f", tf.Text);
  207. Application.Top.Dispose ();
  208. }
  209. private TextField GetTextFieldsInView ()
  210. {
  211. var tf = new TextField { Width = 10 };
  212. var tf2 = new TextField { Y = 1, Width = 10 };
  213. Toplevel top = new ();
  214. top.Add (tf);
  215. top.Add (tf2);
  216. Application.Begin (top);
  217. Assert.Same (tf, top.Focused);
  218. return tf;
  219. }
  220. private TextField GetTextFieldsInViewSuggesting (params string [] suggestions)
  221. {
  222. TextField tf = GetTextFieldsInView ();
  223. tf.Autocomplete = new AppendAutocomplete (tf);
  224. var generator = (SingleWordSuggestionGenerator)tf.Autocomplete.SuggestionGenerator;
  225. generator.AllSuggestions = suggestions.ToList ();
  226. tf.Draw ();
  227. tf.PositionCursor ();
  228. DriverAssert.AssertDriverContentsAre ("", output);
  229. return tf;
  230. }
  231. }