MessageBoxTests.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. using System.Text;
  2. using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.DialogTests;
  5. public class MessageBoxTests
  6. {
  7. private readonly ITestOutputHelper _output;
  8. public MessageBoxTests (ITestOutputHelper output) { _output = output; }
  9. [Fact]
  10. [AutoInitShutdown]
  11. public void KeyBindings_Enter_Causes_Focused_Button_Click_No_Accept ()
  12. {
  13. int result = -1;
  14. var iteration = 0;
  15. int btnAcceptCount = 0;
  16. Application.Iteration += (s, a) =>
  17. {
  18. iteration++;
  19. switch (iteration)
  20. {
  21. case 1:
  22. result = MessageBox.Query (string.Empty, string.Empty, 0, false, "btn0", "btn1");
  23. Application.RequestStop ();
  24. break;
  25. case 2:
  26. // Tab to btn2
  27. Application.OnKeyDown (Key.Tab);
  28. Button btn = Application.Navigation!.GetFocused () as Button;
  29. btn.Accepting += (sender, e) => { btnAcceptCount++; };
  30. // Click
  31. Application.OnKeyDown (Key.Enter);
  32. break;
  33. default:
  34. Assert.Fail ();
  35. break;
  36. }
  37. };
  38. Application.Run ().Dispose ();
  39. Assert.Equal (1, result);
  40. Assert.Equal (1, btnAcceptCount);
  41. }
  42. [Fact]
  43. [AutoInitShutdown]
  44. public void KeyBindings_Esc_Closes ()
  45. {
  46. var result = 999;
  47. var iteration = 0;
  48. Application.Iteration += (s, a) =>
  49. {
  50. iteration++;
  51. switch (iteration)
  52. {
  53. case 1:
  54. result = MessageBox.Query (string.Empty, string.Empty, 0, false, "btn0", "btn1");
  55. Application.RequestStop ();
  56. break;
  57. case 2:
  58. Application.OnKeyDown (Key.Esc);
  59. break;
  60. default:
  61. Assert.Fail ();
  62. break;
  63. }
  64. };
  65. Application.Run ().Dispose ();
  66. Assert.Equal (-1, result);
  67. }
  68. [Fact]
  69. [AutoInitShutdown]
  70. public void KeyBindings_Space_Causes_Focused_Button_Click_No_Accept ()
  71. {
  72. int result = -1;
  73. var iteration = 0;
  74. int btnAcceptCount = 0;
  75. Application.Iteration += (s, a) =>
  76. {
  77. iteration++;
  78. switch (iteration)
  79. {
  80. case 1:
  81. result = MessageBox.Query (string.Empty, string.Empty, 0, false, "btn0", "btn1");
  82. Application.RequestStop ();
  83. break;
  84. case 2:
  85. // Tab to btn2
  86. Application.OnKeyDown (Key.Tab);
  87. Button btn = Application.Navigation!.GetFocused () as Button;
  88. btn.Accepting += (sender, e) => { btnAcceptCount++; };
  89. Application.OnKeyDown (Key.Space);
  90. break;
  91. default:
  92. Assert.Fail ();
  93. break;
  94. }
  95. };
  96. Application.Run ().Dispose ();
  97. Assert.Equal (1, result);
  98. Assert.Equal (1, btnAcceptCount);
  99. }
  100. [Theory]
  101. [InlineData (@"", false, false, 6, 6, 2, 2)]
  102. [InlineData (@"", false, true, 3, 6, 9, 3)]
  103. [InlineData (@"01234\n-----\n01234", false, false, 1, 6, 13, 3)]
  104. [InlineData (@"01234\n-----\n01234", true, false, 1, 5, 13, 4)]
  105. [InlineData (@"0123456789", false, false, 1, 6, 12, 3)]
  106. [InlineData (@"0123456789", false, true, 1, 5, 12, 4)]
  107. [InlineData (@"01234567890123456789", false, true, 1, 5, 13, 4)]
  108. [InlineData (@"01234567890123456789", true, true, 1, 5, 13, 5)]
  109. [InlineData (@"01234567890123456789\n01234567890123456789", false, true, 1, 5, 13, 4)]
  110. [InlineData (@"01234567890123456789\n01234567890123456789", true, true, 1, 4, 13, 7)]
  111. [AutoInitShutdown]
  112. public void Location_And_Size_Correct (string message, bool wrapMessage, bool hasButton, int expectedX, int expectedY, int expectedW, int expectedH)
  113. {
  114. int iterations = -1;
  115. ((FakeDriver)Application.Driver!).SetBufferSize (15, 15); // 15 x 15 gives us enough room for a button with one char (9x1)
  116. Dialog.DefaultShadow = ShadowStyle.None;
  117. Button.DefaultShadow = ShadowStyle.None;
  118. Rectangle mbFrame = Rectangle.Empty;
  119. Application.Iteration += (s, a) =>
  120. {
  121. iterations++;
  122. if (iterations == 0)
  123. {
  124. MessageBox.Query (string.Empty, message, 0, wrapMessage, hasButton ? ["0"] : []);
  125. Application.RequestStop ();
  126. }
  127. else if (iterations == 1)
  128. {
  129. mbFrame = Application.Top!.Frame;
  130. Application.RequestStop ();
  131. }
  132. };
  133. Application.Run ().Dispose ();
  134. Assert.Equal (new (expectedX, expectedY, expectedW, expectedH), mbFrame);
  135. }
  136. [Fact]
  137. [AutoInitShutdown]
  138. public void Message_With_Spaces_WrapMessage_False ()
  139. {
  140. int iterations = -1;
  141. var top = new Toplevel ();
  142. top.BorderStyle = LineStyle.None;
  143. ((FakeDriver)Application.Driver!).SetBufferSize (20, 10);
  144. var btn =
  145. $"{CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} btn {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket}";
  146. // Override CM
  147. MessageBox.DefaultButtonAlignment = Alignment.End;
  148. MessageBox.DefaultBorderStyle = LineStyle.Double;
  149. Dialog.DefaultShadow = ShadowStyle.None;
  150. Button.DefaultShadow = ShadowStyle.None;
  151. Application.Iteration += (s, a) =>
  152. {
  153. iterations++;
  154. if (iterations == 0)
  155. {
  156. var sb = new StringBuilder ();
  157. for (var i = 0; i < 17; i++)
  158. {
  159. sb.Append ("ff ");
  160. }
  161. MessageBox.Query (string.Empty, sb.ToString (), 0, false, "btn");
  162. Application.RequestStop ();
  163. }
  164. else if (iterations == 1)
  165. {
  166. Application.Refresh ();
  167. TestHelpers.AssertDriverContentsWithFrameAre (
  168. @"
  169. ╔════════════════╗
  170. ║ ff ff ff ff ff ║
  171. ║ ⟦► btn ◄⟧║
  172. ╚════════════════╝",
  173. _output
  174. );
  175. Application.RequestStop ();
  176. // Really long text
  177. MessageBox.Query (string.Empty, new string ('f', 500), 0, false, "btn");
  178. }
  179. else if (iterations == 2)
  180. {
  181. Application.Refresh ();
  182. TestHelpers.AssertDriverContentsWithFrameAre (
  183. @"
  184. ╔════════════════╗
  185. ║ffffffffffffffff║
  186. ║ ⟦► btn ◄⟧║
  187. ╚════════════════╝",
  188. _output
  189. );
  190. Application.RequestStop ();
  191. }
  192. };
  193. Application.Run (top);
  194. top.Dispose ();
  195. }
  196. [Fact]
  197. [AutoInitShutdown]
  198. public void Message_With_Spaces_WrapMessage_True ()
  199. {
  200. int iterations = -1;
  201. var top = new Toplevel ();
  202. top.BorderStyle = LineStyle.None;
  203. ((FakeDriver)Application.Driver!).SetBufferSize (20, 10);
  204. var btn =
  205. $"{CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} btn {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket}";
  206. // Override CM
  207. MessageBox.DefaultButtonAlignment = Alignment.End;
  208. MessageBox.DefaultBorderStyle = LineStyle.Double;
  209. Dialog.DefaultShadow = ShadowStyle.None;
  210. Button.DefaultShadow = ShadowStyle.None;
  211. Application.Iteration += (s, a) =>
  212. {
  213. iterations++;
  214. if (iterations == 0)
  215. {
  216. var sb = new StringBuilder ();
  217. for (var i = 0; i < 17; i++)
  218. {
  219. sb.Append ("ff ");
  220. }
  221. MessageBox.Query (string.Empty, sb.ToString (), 0, true, "btn");
  222. Application.RequestStop ();
  223. }
  224. else if (iterations == 1)
  225. {
  226. Application.Refresh ();
  227. TestHelpers.AssertDriverContentsWithFrameAre (
  228. @"
  229. ╔══════════════╗
  230. ║ff ff ff ff ff║
  231. ║ff ff ff ff ff║
  232. ║ff ff ff ff ff║
  233. ║ ff ff ║
  234. ║ ⟦► btn ◄⟧║
  235. ╚══════════════╝",
  236. _output
  237. );
  238. Application.RequestStop ();
  239. // Really long text
  240. MessageBox.Query (string.Empty, new string ('f', 500), 0, true, "btn");
  241. }
  242. else if (iterations == 2)
  243. {
  244. Application.Refresh ();
  245. TestHelpers.AssertDriverContentsWithFrameAre (
  246. @$"
  247. ╔════════════════╗
  248. ║ffffffffffffffff║
  249. ║ffffffffffffffff║
  250. ║ffffffffffffffff║
  251. ║ffffffffffffffff║
  252. ║ffffffffffffffff║
  253. ║ffffffffffffffff║
  254. ║fffffff⟦► btn ◄⟧║
  255. ╚════════════════╝",
  256. _output
  257. );
  258. Application.RequestStop ();
  259. }
  260. };
  261. Application.Run (top);
  262. top.Dispose ();
  263. }
  264. [Theory]
  265. [InlineData (0, 0, "1")]
  266. [InlineData (1, 1, "1")]
  267. [InlineData (7, 5, "1")]
  268. [InlineData (50, 50, "1")]
  269. [InlineData (0, 0, "message")]
  270. [InlineData (1, 1, "message")]
  271. [InlineData (7, 5, "message")]
  272. [InlineData (50, 50, "message")]
  273. [AutoInitShutdown]
  274. public void Size_Not_Default_Message (int height, int width, string message)
  275. {
  276. int iterations = -1;
  277. ((FakeDriver)Application.Driver!).SetBufferSize (100, 100);
  278. Application.Iteration += (s, a) =>
  279. {
  280. iterations++;
  281. if (iterations == 0)
  282. {
  283. MessageBox.Query (height, width, string.Empty, message, null);
  284. Application.RequestStop ();
  285. }
  286. else if (iterations == 1)
  287. {
  288. Application.Refresh ();
  289. Assert.IsType<Dialog> (Application.Top);
  290. Assert.Equal (new (height, width), Application.Top.Frame.Size);
  291. Application.RequestStop ();
  292. }
  293. };
  294. }
  295. [Theory]
  296. [InlineData (0, 0, "1")]
  297. [InlineData (1, 1, "1")]
  298. [InlineData (7, 5, "1")]
  299. [InlineData (50, 50, "1")]
  300. [InlineData (0, 0, "message")]
  301. [InlineData (1, 1, "message")]
  302. [InlineData (7, 5, "message")]
  303. [InlineData (50, 50, "message")]
  304. [AutoInitShutdown]
  305. public void Size_Not_Default_Message_Button (int height, int width, string message)
  306. {
  307. int iterations = -1;
  308. ((FakeDriver)Application.Driver!).SetBufferSize (100, 100);
  309. Application.Iteration += (s, a) =>
  310. {
  311. iterations++;
  312. if (iterations == 0)
  313. {
  314. MessageBox.Query (height, width, string.Empty, message, "_Ok");
  315. Application.RequestStop ();
  316. }
  317. else if (iterations == 1)
  318. {
  319. Application.Refresh ();
  320. Assert.IsType<Dialog> (Application.Top);
  321. Assert.Equal (new (height, width), Application.Top.Frame.Size);
  322. Application.RequestStop ();
  323. }
  324. };
  325. }
  326. [Theory]
  327. [InlineData (0, 0)]
  328. [InlineData (1, 1)]
  329. [InlineData (7, 5)]
  330. [InlineData (50, 50)]
  331. [AutoInitShutdown]
  332. public void Size_Not_Default_No_Message (int height, int width)
  333. {
  334. int iterations = -1;
  335. ((FakeDriver)Application.Driver!).SetBufferSize (100, 100);
  336. Application.Iteration += (s, a) =>
  337. {
  338. iterations++;
  339. if (iterations == 0)
  340. {
  341. MessageBox.Query (height, width, string.Empty, string.Empty, null);
  342. Application.RequestStop ();
  343. }
  344. else if (iterations == 1)
  345. {
  346. Application.Refresh ();
  347. Assert.IsType<Dialog> (Application.Top);
  348. Assert.Equal (new (height, width), Application.Top.Frame.Size);
  349. Application.RequestStop ();
  350. }
  351. };
  352. }
  353. [Fact]
  354. [AutoInitShutdown]
  355. public void UICatalog_AboutBox ()
  356. {
  357. int iterations = -1;
  358. ((FakeDriver)Application.Driver).SetBufferSize (70, 15);
  359. // Override CM
  360. MessageBox.DefaultButtonAlignment = Alignment.End;
  361. MessageBox.DefaultBorderStyle = LineStyle.Double;
  362. Dialog.DefaultShadow = ShadowStyle.None;
  363. Button.DefaultShadow = ShadowStyle.None;
  364. Application.Iteration += (s, a) =>
  365. {
  366. iterations++;
  367. if (iterations == 0)
  368. {
  369. MessageBox.Query (
  370. title: "",
  371. message: UICatalog.UICatalogApp.GetAboutBoxMessage (),
  372. wrapMessage: false,
  373. buttons: "_Ok"
  374. );
  375. Application.RequestStop ();
  376. }
  377. else if (iterations == 1)
  378. {
  379. Application.Refresh ();
  380. string expectedText = """
  381. ┌────────────────────────────────────────────────────────────────────┐
  382. │ ╔══════════════════════════════════════════════════════════╗ │
  383. │ ║ UI Catalog: A comprehensive sample library for ║ │
  384. │ ║ ║ │
  385. │ ║ _______ _ _ _____ _ ║ │
  386. │ ║|__ __| (_) | | / ____| (_)║ │
  387. │ ║ | | ___ _ __ _ __ ___ _ _ __ __ _| || | __ _ _ _ ║ │
  388. │ ║ | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |║ │
  389. │ ║ | | __/ | | | | | | | | | | | (_| | || |__| | |_| | |║ │
  390. │ ║ |_|\___|_| |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|║ │
  391. │ ║ ║ │
  392. │ ║ v2 - Pre-Alpha ║ │
  393. │ ║ ⟦► Ok ◄⟧║ │
  394. │ ╚══════════════════════════════════════════════════════════╝ │
  395. └────────────────────────────────────────────────────────────────────┘
  396. """;
  397. TestHelpers.AssertDriverContentsAre (expectedText, _output);
  398. Application.RequestStop ();
  399. }
  400. };
  401. var top = new Toplevel ();
  402. top.BorderStyle = LineStyle.Single;
  403. Application.Run (top);
  404. top.Dispose ();
  405. }
  406. }