AppendAutocompleteTests.cs 8.6 KB

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