DialogTests.cs 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523
  1. #nullable enable
  2. using UnitTests;
  3. using Xunit.Abstractions;
  4. using static Terminal.Gui.App.Application;
  5. namespace Terminal.Gui.DialogTests;
  6. public class DialogTests (ITestOutputHelper output)
  7. {
  8. [Fact]
  9. [AutoInitShutdown]
  10. public void Add_Button_Works ()
  11. {
  12. RunState? runState = null;
  13. var title = "1234";
  14. var btn1Text = "yes";
  15. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  16. var btn2Text = "no";
  17. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  18. // We test with one button first, but do this to get the width right for 2
  19. int width = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}".Length;
  20. AutoInitShutdownAttribute.FakeResize(new(width, 1));
  21. // Override CM
  22. Dialog.DefaultButtonAlignment = Alignment.Center;
  23. Dialog.DefaultBorderStyle = LineStyle.Single;
  24. Dialog.DefaultShadow = ShadowStyle.None;
  25. Button.DefaultShadow = ShadowStyle.None;
  26. // Default (center)
  27. var dlg = new Dialog
  28. {
  29. Title = title,
  30. Width = width,
  31. Height = 1,
  32. ButtonAlignment = Alignment.Center,
  33. Buttons = [new () { Text = btn1Text }]
  34. };
  35. // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
  36. dlg.Border!.Thickness = new (1, 0, 1, 0);
  37. runState = Begin (dlg);
  38. var buttonRow = $"{Glyphs.VLine} {btn1} {Glyphs.VLine}";
  39. AutoInitShutdownAttribute.RunIteration ();
  40. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  41. // Now add a second button
  42. buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}";
  43. dlg.AddButton (new () { Text = btn2Text });
  44. AutoInitShutdownAttribute.RunIteration ();
  45. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  46. End (runState);
  47. dlg.Dispose ();
  48. // Justify
  49. dlg = new ()
  50. {
  51. Title = title,
  52. Width = width,
  53. Height = 1,
  54. ButtonAlignment = Alignment.Fill,
  55. Buttons = [new () { Text = btn1Text }]
  56. };
  57. // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
  58. dlg.Border!.Thickness = new (1, 0, 1, 0);
  59. runState = Begin (dlg);
  60. AutoInitShutdownAttribute.RunIteration ();
  61. buttonRow = $"{Glyphs.VLine}{btn1} {Glyphs.VLine}";
  62. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  63. // Now add a second button
  64. buttonRow = $"{Glyphs.VLine}{btn1} {btn2}{Glyphs.VLine}";
  65. dlg.AddButton (new () { Text = btn2Text });
  66. AutoInitShutdownAttribute.RunIteration ();
  67. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  68. End (runState);
  69. dlg.Dispose ();
  70. // Right
  71. dlg = new ()
  72. {
  73. Title = title,
  74. Width = width,
  75. Height = 1,
  76. ButtonAlignment = Alignment.End,
  77. Buttons = [new () { Text = btn1Text }]
  78. };
  79. // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
  80. dlg.Border!.Thickness = new (1, 0, 1, 0);
  81. runState = Begin (dlg);
  82. AutoInitShutdownAttribute.RunIteration ();
  83. buttonRow = $"{Glyphs.VLine}{new (' ', width - btn1.Length - 2)}{btn1}{Glyphs.VLine}";
  84. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  85. // Now add a second button
  86. buttonRow = $"{Glyphs.VLine} {btn1} {btn2}{Glyphs.VLine}";
  87. dlg.AddButton (new () { Text = btn2Text });
  88. AutoInitShutdownAttribute.RunIteration ();
  89. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  90. End (runState);
  91. dlg.Dispose ();
  92. // Left
  93. dlg = new ()
  94. {
  95. Title = title,
  96. Width = width,
  97. Height = 1,
  98. ButtonAlignment = Alignment.Start,
  99. Buttons = [new () { Text = btn1Text }]
  100. };
  101. // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
  102. dlg.Border!.Thickness = new (1, 0, 1, 0);
  103. runState = Begin (dlg);
  104. AutoInitShutdownAttribute.RunIteration ();
  105. buttonRow = $"{Glyphs.VLine}{btn1}{new (' ', width - btn1.Length - 2)}{Glyphs.VLine}";
  106. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  107. // Now add a second button
  108. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {Glyphs.VLine}";
  109. dlg.AddButton (new () { Text = btn2Text });
  110. AutoInitShutdownAttribute.RunIteration ();
  111. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  112. End (runState);
  113. dlg.Dispose ();
  114. }
  115. [Fact]
  116. [AutoInitShutdown]
  117. public void ButtonAlignment_Four ()
  118. {
  119. RunState? runState = null;
  120. Dialog.DefaultShadow = ShadowStyle.None;
  121. Button.DefaultShadow = ShadowStyle.None;
  122. var title = "1234";
  123. // E.g "|[ yes ][ no ][ maybe ]|"
  124. var btn1Text = "yes";
  125. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  126. var btn2Text = "no";
  127. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  128. var btn3Text = "maybe";
  129. var btn3 = $"{Glyphs.LeftBracket} {btn3Text} {Glyphs.RightBracket}";
  130. var btn4Text = "never";
  131. var btn4 = $"{Glyphs.LeftBracket} {btn4Text} {Glyphs.RightBracket}";
  132. var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  133. int width = buttonRow.Length;
  134. AutoInitShutdownAttribute.FakeResize(new (buttonRow.Length, 3));
  135. // Default - Center
  136. (runState, Dialog dlg) = BeginButtonTestDialog (
  137. title,
  138. width,
  139. Alignment.Center,
  140. new Button { Text = btn1Text },
  141. new Button { Text = btn2Text },
  142. new Button { Text = btn3Text },
  143. new Button { Text = btn4Text }
  144. );
  145. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  146. End (runState);
  147. dlg.Dispose ();
  148. // Justify
  149. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  150. Assert.Equal (width, buttonRow.Length);
  151. (runState, dlg) = BeginButtonTestDialog (
  152. title,
  153. width,
  154. Alignment.Fill,
  155. new Button { Text = btn1Text },
  156. new Button { Text = btn2Text },
  157. new Button { Text = btn3Text },
  158. new Button { Text = btn4Text }
  159. );
  160. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  161. End (runState);
  162. dlg.Dispose ();
  163. // Right
  164. buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  165. Assert.Equal (width, buttonRow.Length);
  166. (runState, dlg) = BeginButtonTestDialog (
  167. title,
  168. width,
  169. Alignment.End,
  170. new Button { Text = btn1Text },
  171. new Button { Text = btn2Text },
  172. new Button { Text = btn3Text },
  173. new Button { Text = btn4Text }
  174. );
  175. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  176. End (runState);
  177. dlg.Dispose ();
  178. // Left
  179. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  180. Assert.Equal (width, buttonRow.Length);
  181. (runState, dlg) = BeginButtonTestDialog (
  182. title,
  183. width,
  184. Alignment.Start,
  185. new Button { Text = btn1Text },
  186. new Button { Text = btn2Text },
  187. new Button { Text = btn3Text },
  188. new Button { Text = btn4Text }
  189. );
  190. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  191. End (runState);
  192. dlg.Dispose ();
  193. }
  194. [Fact]
  195. [AutoInitShutdown]
  196. public void ButtonAlignment_Four_On_Too_Small_Width ()
  197. {
  198. RunState? runState = null;
  199. Dialog.DefaultShadow = ShadowStyle.None;
  200. Button.DefaultShadow = ShadowStyle.None;
  201. var title = "1234";
  202. // E.g "|[ yes ][ no ][ maybe ][ never ]|"
  203. var btn1Text = "yes";
  204. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  205. var btn2Text = "no";
  206. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  207. var btn3Text = "maybe";
  208. var btn3 = $"{Glyphs.LeftBracket} {btn3Text} {Glyphs.RightBracket}";
  209. var btn4Text = "never";
  210. var btn4 = $"{Glyphs.LeftBracket} {btn4Text} {Glyphs.RightBracket}";
  211. var buttonRow = string.Empty;
  212. var width = 30;
  213. AutoInitShutdownAttribute.FakeResize(new(width, 1));
  214. // Default - Center
  215. buttonRow =
  216. $"{Glyphs.VLine} yes {Glyphs.RightBracket}{btn2}{btn3}{Glyphs.LeftBracket} never{Glyphs.VLine}";
  217. (runState, Dialog dlg) = BeginButtonTestDialog (
  218. title,
  219. width,
  220. Alignment.Center,
  221. new Button { Text = btn1Text },
  222. new Button { Text = btn2Text },
  223. new Button { Text = btn3Text },
  224. new Button { Text = btn4Text }
  225. );
  226. Assert.Equal (new (width, 1), dlg.Frame.Size);
  227. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  228. End (runState);
  229. dlg.Dispose ();
  230. // Justify
  231. buttonRow =
  232. $"{Glyphs.VLine}{Glyphs.LeftBracket} yes {Glyphs.LeftBracket} no {Glyphs.LeftBracket} maybe {Glyphs.LeftBracket} never {Glyphs.RightBracket}{Glyphs.VLine}";
  233. (runState, dlg) = BeginButtonTestDialog (
  234. title,
  235. width,
  236. Alignment.Fill,
  237. new Button { Text = btn1Text },
  238. new Button { Text = btn2Text },
  239. new Button { Text = btn3Text },
  240. new Button { Text = btn4Text }
  241. );
  242. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  243. End (runState);
  244. dlg.Dispose ();
  245. // Right
  246. buttonRow = $"{Glyphs.VLine}es {Glyphs.RightBracket}{btn2}{btn3}{btn4}{Glyphs.VLine}";
  247. Assert.Equal (width, buttonRow.Length);
  248. (runState, dlg) = BeginButtonTestDialog (
  249. title,
  250. width,
  251. Alignment.End,
  252. new Button { Text = btn1Text },
  253. new Button { Text = btn2Text },
  254. new Button { Text = btn3Text },
  255. new Button { Text = btn4Text }
  256. );
  257. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  258. End (runState);
  259. dlg.Dispose ();
  260. // Left
  261. buttonRow = $"{Glyphs.VLine}{btn1}{btn2}{btn3}{Glyphs.LeftBracket} neve{Glyphs.VLine}";
  262. (runState, dlg) = BeginButtonTestDialog (
  263. title,
  264. width,
  265. Alignment.Start,
  266. new Button { Text = btn1Text },
  267. new Button { Text = btn2Text },
  268. new Button { Text = btn3Text },
  269. new Button { Text = btn4Text }
  270. );
  271. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  272. End (runState);
  273. dlg.Dispose ();
  274. }
  275. [Fact]
  276. [AutoInitShutdown]
  277. public void ButtonAlignment_Four_WideOdd ()
  278. {
  279. RunState? runState = null;
  280. Dialog.DefaultShadow = ShadowStyle.None;
  281. Button.DefaultShadow = ShadowStyle.None;
  282. var title = "1234";
  283. // E.g "|[ yes ][ no ][ maybe ]|"
  284. var btn1Text = "really long button 1";
  285. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  286. var btn2Text = "really long button 2";
  287. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  288. var btn3Text = "really long button 3";
  289. var btn3 = $"{Glyphs.LeftBracket} {btn3Text} {Glyphs.RightBracket}";
  290. var btn4Text = "really long button 44"; // 44 is intentional to make length different than rest
  291. var btn4 = $"{Glyphs.LeftBracket} {btn4Text} {Glyphs.RightBracket}";
  292. // Note extra spaces to make dialog even wider
  293. // 123456 1234567
  294. var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  295. int width = buttonRow.Length;
  296. AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 1));
  297. // Default - Center
  298. (runState, Dialog dlg) = BeginButtonTestDialog (
  299. title,
  300. width,
  301. Alignment.Center,
  302. new Button { Text = btn1Text },
  303. new Button { Text = btn2Text },
  304. new Button { Text = btn3Text },
  305. new Button { Text = btn4Text }
  306. );
  307. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  308. End (runState);
  309. dlg.Dispose ();
  310. // Justify
  311. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  312. Assert.Equal (width, buttonRow.Length);
  313. (runState, dlg) = BeginButtonTestDialog (
  314. title,
  315. width,
  316. Alignment.Fill,
  317. new Button { Text = btn1Text },
  318. new Button { Text = btn2Text },
  319. new Button { Text = btn3Text },
  320. new Button { Text = btn4Text }
  321. );
  322. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  323. End (runState);
  324. dlg.Dispose ();
  325. // Right
  326. buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  327. Assert.Equal (width, buttonRow.Length);
  328. (runState, dlg) = BeginButtonTestDialog (
  329. title,
  330. width,
  331. Alignment.End,
  332. new Button { Text = btn1Text },
  333. new Button { Text = btn2Text },
  334. new Button { Text = btn3Text },
  335. new Button { Text = btn4Text }
  336. );
  337. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  338. End (runState);
  339. dlg.Dispose ();
  340. // Left
  341. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  342. Assert.Equal (width, buttonRow.Length);
  343. (runState, dlg) = BeginButtonTestDialog (
  344. title,
  345. width,
  346. Alignment.Start,
  347. new Button { Text = btn1Text },
  348. new Button { Text = btn2Text },
  349. new Button { Text = btn3Text },
  350. new Button { Text = btn4Text }
  351. );
  352. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  353. End (runState);
  354. dlg.Dispose ();
  355. }
  356. [Fact]
  357. [AutoInitShutdown]
  358. public void ButtonAlignment_Four_Wider ()
  359. {
  360. RunState? runState = null;
  361. Dialog.DefaultShadow = ShadowStyle.None;
  362. Button.DefaultShadow = ShadowStyle.None;
  363. var title = "1234";
  364. // E.g "|[ yes ][ no ][ maybe ]|"
  365. var btn1Text = "yes";
  366. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  367. var btn2Text = "no";
  368. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  369. var btn3Text = "你你你你你"; // This is a wide char
  370. var btn3 = $"{Glyphs.LeftBracket} {btn3Text} {Glyphs.RightBracket}";
  371. // Requires a Nerd Font
  372. var btn4Text = "\uE36E\uE36F\uE370\uE371\uE372\uE373";
  373. var btn4 = $"{Glyphs.LeftBracket} {btn4Text} {Glyphs.RightBracket}";
  374. // Note extra spaces to make dialog even wider
  375. // 123456 123456
  376. var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  377. int width = buttonRow.GetColumns ();
  378. AutoInitShutdownAttribute.FakeResize(new(width, 3));
  379. // Default - Center
  380. (runState, Dialog dlg) = BeginButtonTestDialog (
  381. title,
  382. width,
  383. Alignment.Center,
  384. new Button { Text = btn1Text },
  385. new Button { Text = btn2Text },
  386. new Button { Text = btn3Text },
  387. new Button { Text = btn4Text }
  388. );
  389. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  390. End (runState);
  391. dlg.Dispose ();
  392. // Justify
  393. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  394. Assert.Equal (width, buttonRow.GetColumns ());
  395. (runState, dlg) = BeginButtonTestDialog (
  396. title,
  397. width,
  398. Alignment.Fill,
  399. new Button { Text = btn1Text },
  400. new Button { Text = btn2Text },
  401. new Button { Text = btn3Text },
  402. new Button { Text = btn4Text }
  403. );
  404. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  405. End (runState);
  406. dlg.Dispose ();
  407. // Right
  408. buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4}{Glyphs.VLine}";
  409. Assert.Equal (width, buttonRow.GetColumns ());
  410. (runState, dlg) = BeginButtonTestDialog (
  411. title,
  412. width,
  413. Alignment.End,
  414. new Button { Text = btn1Text },
  415. new Button { Text = btn2Text },
  416. new Button { Text = btn3Text },
  417. new Button { Text = btn4Text }
  418. );
  419. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  420. End (runState);
  421. dlg.Dispose ();
  422. // Left
  423. buttonRow = $"{Glyphs.VLine}{btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}";
  424. Assert.Equal (width, buttonRow.GetColumns ());
  425. (runState, dlg) = BeginButtonTestDialog (
  426. title,
  427. width,
  428. Alignment.Start,
  429. new Button { Text = btn1Text },
  430. new Button { Text = btn2Text },
  431. new Button { Text = btn3Text },
  432. new Button { Text = btn4Text }
  433. );
  434. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  435. End (runState);
  436. dlg.Dispose ();
  437. }
  438. [Fact]
  439. [AutoInitShutdown]
  440. public void ButtonAlignment_One ()
  441. {
  442. RunState? runState = null;
  443. Dialog.DefaultShadow = ShadowStyle.None;
  444. Button.DefaultShadow = ShadowStyle.None;
  445. var title = "1234";
  446. // E.g "|[ ok ]|"
  447. var btnText = "ok";
  448. var buttonRow =
  449. $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  450. int width = buttonRow.Length;
  451. AutoInitShutdownAttribute.FakeResize(new(width, 1));
  452. (runState, Dialog dlg) = BeginButtonTestDialog (
  453. title,
  454. width,
  455. Alignment.Center,
  456. new Button { Text = btnText }
  457. );
  458. // Center
  459. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  460. End (runState);
  461. dlg.Dispose ();
  462. // Justify
  463. buttonRow =
  464. $"{Glyphs.VLine}{Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  465. Assert.Equal (width, buttonRow.Length);
  466. (runState, dlg) = BeginButtonTestDialog (
  467. title,
  468. width,
  469. Alignment.Fill,
  470. new Button { Text = btnText }
  471. );
  472. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  473. End (runState);
  474. dlg.Dispose ();
  475. // Right
  476. buttonRow =
  477. $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket}{Glyphs.VLine}";
  478. Assert.Equal (width, buttonRow.Length);
  479. (runState, dlg) = BeginButtonTestDialog (
  480. title,
  481. width,
  482. Alignment.End,
  483. new Button { Text = btnText }
  484. );
  485. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  486. End (runState);
  487. dlg.Dispose ();
  488. // Left
  489. buttonRow =
  490. $"{Glyphs.VLine}{Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  491. Assert.Equal (width, buttonRow.Length);
  492. (runState, dlg) = BeginButtonTestDialog (
  493. title,
  494. width,
  495. Alignment.Start,
  496. new Button { Text = btnText }
  497. );
  498. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  499. End (runState);
  500. dlg.Dispose ();
  501. // Wider
  502. buttonRow =
  503. $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  504. width = buttonRow.Length;
  505. AutoInitShutdownAttribute.FakeResize(new(width, 1));
  506. (runState, dlg) = BeginButtonTestDialog (
  507. title,
  508. width,
  509. Alignment.Center,
  510. new Button { Text = btnText }
  511. );
  512. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  513. End (runState);
  514. dlg.Dispose ();
  515. // Justify
  516. buttonRow =
  517. $"{Glyphs.VLine}{Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  518. Assert.Equal (width, buttonRow.Length);
  519. (runState, dlg) = BeginButtonTestDialog (
  520. title,
  521. width,
  522. Alignment.Fill,
  523. new Button { Text = btnText }
  524. );
  525. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  526. End (runState);
  527. dlg.Dispose ();
  528. // Right
  529. buttonRow =
  530. $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket}{Glyphs.VLine}";
  531. Assert.Equal (width, buttonRow.Length);
  532. (runState, dlg) = BeginButtonTestDialog (
  533. title,
  534. width,
  535. Alignment.End,
  536. new Button { Text = btnText }
  537. );
  538. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  539. End (runState);
  540. dlg.Dispose ();
  541. // Left
  542. buttonRow =
  543. $"{Glyphs.VLine}{Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  544. Assert.Equal (width, buttonRow.Length);
  545. (runState, dlg) = BeginButtonTestDialog (
  546. title,
  547. width,
  548. Alignment.Start,
  549. new Button { Text = btnText }
  550. );
  551. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  552. End (runState);
  553. dlg.Dispose ();
  554. }
  555. [Fact]
  556. [AutoInitShutdown]
  557. public void ButtonAlignment_Three ()
  558. {
  559. RunState? runState = null;
  560. Dialog.DefaultShadow = ShadowStyle.None;
  561. Button.DefaultShadow = ShadowStyle.None;
  562. var title = "1234";
  563. // E.g "|[ yes ][ no ][ maybe ]|"
  564. var btn1Text = "yes";
  565. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  566. var btn2Text = "no";
  567. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  568. var btn3Text = "maybe";
  569. var btn3 = $"{Glyphs.LeftBracket} {btn3Text} {Glyphs.RightBracket}";
  570. var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {btn3} {Glyphs.VLine}";
  571. int width = buttonRow.Length;
  572. AutoInitShutdownAttribute.FakeResize(new(buttonRow.Length, 3));
  573. (runState, Dialog dlg) = BeginButtonTestDialog (
  574. title,
  575. width,
  576. Alignment.Center,
  577. new Button { Text = btn1Text },
  578. new Button { Text = btn2Text },
  579. new Button { Text = btn3Text }
  580. );
  581. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  582. End (runState);
  583. dlg.Dispose ();
  584. // Justify
  585. buttonRow = $@"{Glyphs.VLine}{btn1} {btn2} {btn3}{Glyphs.VLine}";
  586. Assert.Equal (width, buttonRow.Length);
  587. (runState, dlg) = BeginButtonTestDialog (
  588. title,
  589. width,
  590. Alignment.Fill,
  591. new Button { Text = btn1Text },
  592. new Button { Text = btn2Text },
  593. new Button { Text = btn3Text }
  594. );
  595. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  596. End (runState);
  597. dlg.Dispose ();
  598. // Right
  599. buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {btn3}{Glyphs.VLine}";
  600. Assert.Equal (width, buttonRow.Length);
  601. (runState, dlg) = BeginButtonTestDialog (
  602. title,
  603. width,
  604. Alignment.End,
  605. new Button { Text = btn1Text },
  606. new Button { Text = btn2Text },
  607. new Button { Text = btn3Text }
  608. );
  609. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  610. End (runState);
  611. dlg.Dispose ();
  612. // Left
  613. buttonRow = $@"{Glyphs.VLine}{btn1} {btn2} {btn3} {Glyphs.VLine}";
  614. Assert.Equal (width, buttonRow.Length);
  615. (runState, dlg) = BeginButtonTestDialog (
  616. title,
  617. width,
  618. Alignment.Start,
  619. new Button { Text = btn1Text },
  620. new Button { Text = btn2Text },
  621. new Button { Text = btn3Text }
  622. );
  623. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  624. End (runState);
  625. dlg.Dispose ();
  626. }
  627. [Fact]
  628. [AutoInitShutdown]
  629. public void ButtonAlignment_Two ()
  630. {
  631. RunState? runState = null;
  632. Dialog.DefaultShadow = ShadowStyle.None;
  633. Button.DefaultShadow = ShadowStyle.None;
  634. var title = "1234";
  635. // E.g "|[ yes ][ no ]|"
  636. var btn1Text = "yes";
  637. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  638. var btn2Text = "no";
  639. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  640. var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}";
  641. int width = buttonRow.Length;
  642. AutoInitShutdownAttribute.FakeResize(new(buttonRow.Length, 3));
  643. (runState, Dialog dlg) = BeginButtonTestDialog (
  644. title,
  645. width,
  646. Alignment.Center,
  647. new Button { Text = btn1Text },
  648. new Button { Text = btn2Text }
  649. );
  650. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  651. End (runState);
  652. dlg.Dispose ();
  653. // Justify
  654. buttonRow = $@"{Glyphs.VLine}{btn1} {btn2}{Glyphs.VLine}";
  655. Assert.Equal (width, buttonRow.Length);
  656. (runState, dlg) = BeginButtonTestDialog (
  657. title,
  658. width,
  659. Alignment.Fill,
  660. new Button { Text = btn1Text },
  661. new Button { Text = btn2Text }
  662. );
  663. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  664. End (runState);
  665. dlg.Dispose ();
  666. // Right
  667. buttonRow = $@"{Glyphs.VLine} {btn1} {btn2}{Glyphs.VLine}";
  668. Assert.Equal (width, buttonRow.Length);
  669. (runState, dlg) = BeginButtonTestDialog (
  670. title,
  671. width,
  672. Alignment.End,
  673. new Button { Text = btn1Text },
  674. new Button { Text = btn2Text }
  675. );
  676. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  677. End (runState);
  678. dlg.Dispose ();
  679. // Left
  680. buttonRow = $@"{Glyphs.VLine}{btn1} {btn2} {Glyphs.VLine}";
  681. Assert.Equal (width, buttonRow.Length);
  682. (runState, dlg) = BeginButtonTestDialog (
  683. title,
  684. width,
  685. Alignment.Start,
  686. new Button { Text = btn1Text },
  687. new Button { Text = btn2Text }
  688. );
  689. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  690. End (runState);
  691. dlg.Dispose ();
  692. }
  693. [Fact]
  694. [AutoInitShutdown]
  695. public void ButtonAlignment_Two_Hidden ()
  696. {
  697. RunState? runState = null;
  698. var firstIteration = false;
  699. Dialog.DefaultShadow = ShadowStyle.None;
  700. Button.DefaultShadow = ShadowStyle.None;
  701. var title = "1234";
  702. // E.g "|[ yes ][ no ]|"
  703. var btn1Text = "yes";
  704. var btn1 = $"{Glyphs.LeftBracket} {btn1Text} {Glyphs.RightBracket}";
  705. var btn2Text = "no";
  706. var btn2 = $"{Glyphs.LeftBracket} {btn2Text} {Glyphs.RightBracket}";
  707. var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}";
  708. int width = buttonRow.Length;
  709. AutoInitShutdownAttribute.FakeResize(new(buttonRow.Length, 3));
  710. Dialog dlg = null;
  711. Button button1, button2;
  712. // Default (Center)
  713. button1 = new () { Text = btn1Text };
  714. button2 = new () { Text = btn2Text };
  715. (runState, dlg) = BeginButtonTestDialog (title, width, Alignment.Center, button1, button2);
  716. button1.Visible = false;
  717. AutoInitShutdownAttribute.RunIteration ();
  718. buttonRow = $@"{Glyphs.VLine} {btn2} {Glyphs.VLine}";
  719. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  720. End (runState);
  721. dlg.Dispose ();
  722. // Justify
  723. Assert.Equal (width, buttonRow.Length);
  724. button1 = new () { Text = btn1Text };
  725. button2 = new () { Text = btn2Text };
  726. (runState, dlg) = BeginButtonTestDialog (title, width, Alignment.Fill, button1, button2);
  727. button1.Visible = false;
  728. AutoInitShutdownAttribute.RunIteration ();
  729. buttonRow = $@"{Glyphs.VLine} {btn2}{Glyphs.VLine}";
  730. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  731. End (runState);
  732. dlg.Dispose ();
  733. // Right
  734. Assert.Equal (width, buttonRow.Length);
  735. button1 = new () { Text = btn1Text };
  736. button2 = new () { Text = btn2Text };
  737. (runState, dlg) = BeginButtonTestDialog (title, width, Alignment.End, button1, button2);
  738. button1.Visible = false;
  739. AutoInitShutdownAttribute.RunIteration ();
  740. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  741. End (runState);
  742. dlg.Dispose ();
  743. // Left
  744. Assert.Equal (width, buttonRow.Length);
  745. button1 = new () { Text = btn1Text };
  746. button2 = new () { Text = btn2Text };
  747. (runState, dlg) = BeginButtonTestDialog (title, width, Alignment.Start, button1, button2);
  748. button1.Visible = false;
  749. AutoInitShutdownAttribute.RunIteration ();
  750. buttonRow = $@"{Glyphs.VLine} {btn2} {Glyphs.VLine}";
  751. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  752. End (runState);
  753. dlg.Dispose ();
  754. }
  755. [Fact]
  756. [AutoInitShutdown]
  757. public void Dialog_In_Window_With_Size_One_Button_Aligns ()
  758. {
  759. AutoInitShutdownAttribute.FakeResize(new(20, 5));
  760. // Override CM
  761. Window.DefaultBorderStyle = LineStyle.Single;
  762. Dialog.DefaultButtonAlignment = Alignment.Center;
  763. Dialog.DefaultBorderStyle = LineStyle.Single;
  764. Dialog.DefaultShadow = ShadowStyle.None;
  765. Button.DefaultShadow = ShadowStyle.None;
  766. var win = new Window ();
  767. var iterations = 0;
  768. Iteration += (s, a) =>
  769. {
  770. if (++iterations > 2)
  771. {
  772. RequestStop ();
  773. }
  774. };
  775. var btn = $"{Glyphs.LeftBracket} Ok {Glyphs.RightBracket}";
  776. win.Loaded += (s, a) =>
  777. {
  778. var dlg = new Dialog { Width = 18, Height = 3, Buttons = [new () { Text = "Ok" }] };
  779. dlg.Loaded += (s, a) =>
  780. {
  781. AutoInitShutdownAttribute.RunIteration ();
  782. var expected = @$"
  783. ┌──────────────────┐
  784. │┌────────────────┐│
  785. ││ {btn} ││
  786. │└────────────────┘│
  787. └──────────────────┘";
  788. _ = DriverAssert.AssertDriverContentsWithFrameAre (expected, output);
  789. };
  790. Run (dlg);
  791. dlg.Dispose ();
  792. };
  793. Run (win);
  794. win.Dispose ();
  795. }
  796. [Theory]
  797. [AutoInitShutdown]
  798. [InlineData (
  799. 5,
  800. @"
  801. ┌┌───────────────┐─┐
  802. ││ │ │
  803. ││ ⟦ Ok ⟧ │ │
  804. │└───────────────┘ │
  805. └──────────────────┘"
  806. )]
  807. [InlineData (
  808. 6,
  809. @"
  810. ┌┌───────────────┐─┐
  811. ││ │ │
  812. ││ │ │
  813. ││ ⟦ Ok ⟧ │ │
  814. │└───────────────┘ │
  815. └──────────────────┘"
  816. )]
  817. [InlineData (
  818. 7,
  819. @"
  820. ┌──────────────────┐
  821. │┌───────────────┐ │
  822. ││ │ │
  823. ││ │ │
  824. ││ ⟦ Ok ⟧ │ │
  825. │└───────────────┘ │
  826. └──────────────────┘"
  827. )]
  828. [InlineData (
  829. 8,
  830. @"
  831. ┌──────────────────┐
  832. │┌───────────────┐ │
  833. ││ │ │
  834. ││ │ │
  835. ││ │ │
  836. ││ ⟦ Ok ⟧ │ │
  837. │└───────────────┘ │
  838. └──────────────────┘"
  839. )]
  840. [InlineData (
  841. 9,
  842. @"
  843. ┌──────────────────┐
  844. │┌───────────────┐ │
  845. ││ │ │
  846. ││ │ │
  847. ││ │ │
  848. ││ │ │
  849. ││ ⟦ Ok ⟧ │ │
  850. │└───────────────┘ │
  851. └──────────────────┘"
  852. )]
  853. public void Dialog_In_Window_Without_Size_One_Button_Aligns (int height, string expected)
  854. {
  855. AutoInitShutdownAttribute.FakeResize(new (20, height));
  856. var win = new Window ();
  857. int iterations = -1;
  858. // Override CM
  859. Dialog.DefaultButtonAlignment = Alignment.Center;
  860. Dialog.DefaultBorderStyle = LineStyle.Single;
  861. Dialog.DefaultShadow = ShadowStyle.None;
  862. Button.DefaultShadow = ShadowStyle.None;
  863. Iteration += (s, a) =>
  864. {
  865. iterations++;
  866. if (iterations == 0)
  867. {
  868. var dlg = new Dialog
  869. {
  870. Buttons = [new () { Text = "Ok" }],
  871. Width = Dim.Percent (85),
  872. Height = Dim.Percent (85)
  873. };
  874. Run (dlg);
  875. dlg.Dispose ();
  876. }
  877. else if (iterations == 1)
  878. {
  879. AutoInitShutdownAttribute.RunIteration ();
  880. // BUGBUG: This seems wrong; is it a bug in Dim.Percent(85)?? No
  881. _ = DriverAssert.AssertDriverContentsWithFrameAre (expected, output);
  882. }
  883. else
  884. {
  885. RequestStop ();
  886. }
  887. };
  888. Run (win);
  889. win.Dispose ();
  890. }
  891. [Fact]
  892. [AutoInitShutdown]
  893. public void Dialog_Opened_From_Another_Dialog ()
  894. {
  895. AutoInitShutdownAttribute.FakeResize(new (30, 10));
  896. // Override CM
  897. Dialog.DefaultButtonAlignment = Alignment.Center;
  898. Dialog.DefaultBorderStyle = LineStyle.Single;
  899. Dialog.DefaultShadow = ShadowStyle.None;
  900. Button.DefaultShadow = ShadowStyle.None;
  901. var btn1 = new Button { Text = "press me 1" };
  902. Button? btn2 = null;
  903. Button? btn3 = null;
  904. string? expected = null;
  905. btn1.Accepting += (s, e) =>
  906. {
  907. btn2 = new () { Text = "Show Sub" };
  908. btn3 = new () { Text = "Close" };
  909. btn3.Accepting += (s, e) => RequestStop ();
  910. btn2.Accepting += (s, e) =>
  911. {
  912. // Don't test MessageBox in Dialog unit tests!
  913. var subBtn = new Button { Text = "Ok", IsDefault = true };
  914. var subDlg = new Dialog { Text = "ya", Width = 20, Height = 5, Buttons = [subBtn] };
  915. subBtn.Accepting += (s, e) => RequestStop (subDlg);
  916. Run (subDlg);
  917. };
  918. var dlg = new Dialog
  919. {
  920. Buttons = [btn2, btn3],
  921. Width = Dim.Percent (85),
  922. Height = Dim.Percent (85)
  923. };
  924. Run (dlg);
  925. dlg.Dispose ();
  926. };
  927. var btn =
  928. $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} Ok {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}";
  929. int iterations = -1;
  930. Iteration += (s, a) =>
  931. {
  932. iterations++;
  933. switch (iterations)
  934. {
  935. case 0:
  936. Top!.SetNeedsLayout ();
  937. Top.SetNeedsDraw ();
  938. break;
  939. case 1:
  940. Assert.False (btn1.NewKeyDownEvent (Key.Space));
  941. break;
  942. // Now this happens on iteration 3 because Space triggers Run on the new dialog which itself causes another iteration
  943. // as it starts. Meaning we haven't exited case 1 when we enter case 2 from next Run stack frame.
  944. case 3:
  945. expected = @$"
  946. ┌───────────────────────┐
  947. │ │
  948. │ │
  949. │ │
  950. │ │
  951. │ │
  952. │{Glyphs.LeftBracket} Show Sub {Glyphs.RightBracket} {Glyphs.LeftBracket} Close {Glyphs.RightBracket} │
  953. └───────────────────────┘";
  954. DriverAssert.AssertDriverContentsWithFrameAre (expected, output);
  955. Assert.False (btn2!.NewKeyDownEvent (Key.Space));
  956. break;
  957. case 5:
  958. DriverAssert.AssertDriverContentsWithFrameAre (
  959. @$"
  960. ┌───────────────────────┐
  961. │ ┌──────────────────┐ │
  962. │ │ya │ │
  963. │ │ │ │
  964. │ │ {btn} │ │
  965. │ └──────────────────┘ │
  966. │{Glyphs.LeftBracket} Show Sub {Glyphs.RightBracket} {Glyphs.LeftBracket} Close {Glyphs.RightBracket} │
  967. └───────────────────────┘",
  968. output
  969. );
  970. Assert.False (Top!.NewKeyDownEvent (Key.Enter));
  971. break;
  972. case 7:
  973. DriverAssert.AssertDriverContentsWithFrameAre (expected, output);
  974. Assert.False (btn3!.NewKeyDownEvent (Key.Space));
  975. break;
  976. case 9:
  977. DriverAssert.AssertDriverContentsWithFrameAre ("", output);
  978. RequestStop ();
  979. break;
  980. }
  981. };
  982. Run ().Dispose ();
  983. Shutdown ();
  984. Assert.Equal (9, iterations);
  985. }
  986. [Fact]
  987. [AutoInitShutdown]
  988. public void FileDialog_FileSystemWatcher ()
  989. {
  990. for (var i = 0; i < 8; i++)
  991. {
  992. var fd = new FileDialog ();
  993. fd.Ready += (s, e) => RequestStop ();
  994. Run (fd);
  995. fd.Dispose ();
  996. }
  997. }
  998. [Fact]
  999. [AutoInitShutdown]
  1000. public void Location_Default ()
  1001. {
  1002. var d = new Dialog
  1003. {
  1004. Width = Dim.Percent (85),
  1005. Height = Dim.Percent (85)
  1006. };
  1007. Begin (d);
  1008. AutoInitShutdownAttribute.FakeResize(new(100, 100));
  1009. // Default location is centered, so 100 / 2 - 85 / 2 = 7
  1010. var expected = 7;
  1011. Assert.Equal (new (expected, expected), d.Frame.Location);
  1012. d.Dispose ();
  1013. }
  1014. [Fact]
  1015. [AutoInitShutdown]
  1016. public void Location_Not_Default ()
  1017. {
  1018. var d = new Dialog { X = 1, Y = 1 };
  1019. Begin (d);
  1020. AutoInitShutdownAttribute.FakeResize(new(100, 100));
  1021. // Default location is centered, so 100 / 2 - 85 / 2 = 7
  1022. var expected = 1;
  1023. Assert.Equal (new (expected, expected), d.Frame.Location);
  1024. d.Dispose ();
  1025. }
  1026. [Fact]
  1027. [AutoInitShutdown]
  1028. public void Location_When_Application_Top_Not_Default ()
  1029. {
  1030. // Override CM
  1031. Window.DefaultBorderStyle = LineStyle.Single;
  1032. Dialog.DefaultButtonAlignment = Alignment.Center;
  1033. Dialog.DefaultBorderStyle = LineStyle.Single;
  1034. Dialog.DefaultShadow = ShadowStyle.None;
  1035. Button.DefaultShadow = ShadowStyle.None;
  1036. var expected = 5;
  1037. var d = new Dialog { X = expected, Y = expected, Height = 5, Width = 5 };
  1038. Begin (d);
  1039. AutoInitShutdownAttribute.FakeResize(new(20, 10));
  1040. // Default location is centered, so 100 / 2 - 85 / 2 = 7
  1041. Assert.Equal (new (expected, expected), d.Frame.Location);
  1042. DriverAssert.AssertDriverContentsWithFrameAre (
  1043. @"
  1044. ┌───┐
  1045. │ │
  1046. │ │
  1047. │ │
  1048. └───┘",
  1049. output
  1050. );
  1051. d.Dispose ();
  1052. }
  1053. [Fact]
  1054. [AutoInitShutdown]
  1055. public void One_Button_Works ()
  1056. {
  1057. RunState? runState = null;
  1058. Button.DefaultShadow = ShadowStyle.None;
  1059. var title = "";
  1060. var btnText = "ok";
  1061. var buttonRow =
  1062. $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}";
  1063. int width = buttonRow.Length;
  1064. AutoInitShutdownAttribute.FakeResize(new(buttonRow.Length, 10));
  1065. (runState, Dialog dlg) = BeginButtonTestDialog (
  1066. title,
  1067. width,
  1068. Alignment.Center,
  1069. new Button { Text = btnText }
  1070. );
  1071. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  1072. End (runState);
  1073. dlg.Dispose ();
  1074. }
  1075. [Fact]
  1076. [AutoInitShutdown]
  1077. public void Size_Default ()
  1078. {
  1079. var d = new Dialog
  1080. {
  1081. Width = Dim.Percent (85),
  1082. Height = Dim.Percent (85)
  1083. };
  1084. Begin (d);
  1085. AutoInitShutdownAttribute.FakeResize(new(100, 100));
  1086. // Default size is Percent(85)
  1087. Assert.Equal (new ((int)(100 * .85), (int)(100 * .85)), d.Frame.Size);
  1088. d.Dispose ();
  1089. }
  1090. [Fact]
  1091. [AutoInitShutdown]
  1092. public void Size_Not_Default ()
  1093. {
  1094. Dialog.DefaultShadow = ShadowStyle.None;
  1095. Button.DefaultShadow = ShadowStyle.None;
  1096. var d = new Dialog { Width = 50, Height = 50 };
  1097. Begin (d);
  1098. AutoInitShutdownAttribute.FakeResize(new(100, 100));
  1099. // Default size is Percent(85)
  1100. Assert.Equal (new (50, 50), d.Frame.Size);
  1101. d.Dispose ();
  1102. }
  1103. [Fact]
  1104. [AutoInitShutdown]
  1105. public void Zero_Buttons_Works ()
  1106. {
  1107. RunState? runState = null;
  1108. var title = "1234";
  1109. var buttonRow = $"{Glyphs.VLine} {Glyphs.VLine}";
  1110. int width = buttonRow.Length;
  1111. AutoInitShutdownAttribute.FakeResize(new(buttonRow.Length, 3));
  1112. (runState, Dialog dlg) = BeginButtonTestDialog (title, width, Alignment.Center, null);
  1113. DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output);
  1114. End (runState);
  1115. dlg.Dispose ();
  1116. }
  1117. private (RunState, Dialog) BeginButtonTestDialog (
  1118. string title,
  1119. int width,
  1120. Alignment align,
  1121. params Button [] btns
  1122. )
  1123. {
  1124. // Override CM
  1125. Dialog.DefaultButtonAlignment = Alignment.Center;
  1126. Dialog.DefaultBorderStyle = LineStyle.Single;
  1127. Dialog.DefaultShadow = ShadowStyle.None;
  1128. Button.DefaultShadow = ShadowStyle.None;
  1129. var dlg = new Dialog
  1130. {
  1131. Title = title,
  1132. X = 0,
  1133. Y = 0,
  1134. Width = width,
  1135. Height = 1,
  1136. ButtonAlignment = align,
  1137. Buttons = btns
  1138. };
  1139. // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
  1140. dlg.Border!.Thickness = new (1, 0, 1, 0);
  1141. RunState runState = Begin (dlg);
  1142. dlg.SetNeedsDraw ();
  1143. dlg.SetNeedsLayout ();
  1144. AutoInitShutdownAttribute.RunIteration ();
  1145. return (runState, dlg);
  1146. }
  1147. [Fact]
  1148. [AutoInitShutdown]
  1149. public void Run_Does_Not_Dispose_Dialog ()
  1150. {
  1151. var top = new Toplevel ();
  1152. Dialog dlg = new ();
  1153. dlg.Ready += Dlg_Ready;
  1154. Run (dlg);
  1155. #if DEBUG_IDISPOSABLE
  1156. Assert.False (dlg.WasDisposed);
  1157. Assert.False (Top!.WasDisposed);
  1158. Assert.NotEqual (top, Top);
  1159. Assert.Equal (dlg, Top);
  1160. #endif
  1161. // dlg wasn't disposed yet and it's possible to access to his properties
  1162. Assert.False (dlg.Canceled);
  1163. Assert.NotNull (dlg);
  1164. dlg.Canceled = true;
  1165. Assert.True (dlg.Canceled);
  1166. dlg.Dispose ();
  1167. top.Dispose ();
  1168. #if DEBUG_IDISPOSABLE
  1169. Assert.True (dlg.WasDisposed);
  1170. Assert.True (Top.WasDisposed);
  1171. Assert.NotNull (Top);
  1172. #endif
  1173. Shutdown ();
  1174. Assert.Null (Top);
  1175. return;
  1176. void Dlg_Ready (object? sender, EventArgs e) { RequestStop (); }
  1177. }
  1178. [Fact]
  1179. [AutoInitShutdown]
  1180. public void Can_Access_Cancel_Property_After_Run ()
  1181. {
  1182. Dialog dlg = new ();
  1183. dlg.Ready += Dlg_Ready;
  1184. Run (dlg);
  1185. #if DEBUG_IDISPOSABLE
  1186. Assert.False (dlg.WasDisposed);
  1187. Assert.False (Top!.WasDisposed);
  1188. Assert.Equal (dlg, Top);
  1189. #endif
  1190. Assert.True (dlg.Canceled);
  1191. // Run it again is possible because it isn't disposed yet
  1192. Run (dlg);
  1193. // Run another view without dispose the prior will throw an assertion
  1194. #if DEBUG_IDISPOSABLE
  1195. Dialog dlg2 = new ();
  1196. dlg2.Ready += Dlg_Ready;
  1197. // Exception exception = Record.Exception (() => Run (dlg2));
  1198. // Assert.NotNull (exception);
  1199. dlg.Dispose ();
  1200. // Now it's possible to tun dlg2 without throw
  1201. Run (dlg2);
  1202. Assert.True (dlg.WasDisposed);
  1203. Assert.False (Top.WasDisposed);
  1204. Assert.Equal (dlg2, Top);
  1205. Assert.False (dlg2.WasDisposed);
  1206. dlg2.Dispose ();
  1207. // tznind REMOVED: Why wouldn't you be able to read cancelled after dispose - that makes no sense
  1208. // Now an assertion will throw accessing the Canceled property
  1209. //var exception = Record.Exception (() => Assert.True (dlg.Canceled))!;
  1210. //Assert.NotNull (exception);
  1211. //Assert.StartsWith ("Cannot access a disposed object.", exception.Message);
  1212. Assert.True (Top.WasDisposed);
  1213. Shutdown ();
  1214. Assert.True (dlg2.WasDisposed);
  1215. Assert.Null (Top);
  1216. #endif
  1217. return;
  1218. void Dlg_Ready (object? sender, EventArgs e)
  1219. {
  1220. ((Dialog)sender!).Canceled = true;
  1221. RequestStop ();
  1222. }
  1223. }
  1224. [Fact]
  1225. [AutoInitShutdown]
  1226. public void Modal_Captures_All_Mouse ()
  1227. {
  1228. Toplevel top = new Toplevel ()
  1229. {
  1230. Id = "top",
  1231. };
  1232. var d = new Dialog
  1233. {
  1234. Width = 10,
  1235. Height = 10,
  1236. X = 1,
  1237. Y = 1
  1238. };
  1239. AutoInitShutdownAttribute.FakeResize(new(20, 20));
  1240. int iterations = 0;
  1241. Iteration += (s, a) =>
  1242. {
  1243. if (++iterations > 2)
  1244. {
  1245. RequestStop ();
  1246. }
  1247. if (iterations == 1)
  1248. {
  1249. Application.Run (d);
  1250. d.Dispose ();
  1251. }
  1252. else if (iterations == 2)
  1253. {
  1254. // Mouse click outside of dialog
  1255. Application.RaiseMouseEvent (new MouseEventArgs () { Flags = MouseFlags.Button1Clicked, ScreenPosition = new Point (0, 0) });
  1256. }
  1257. };
  1258. top.MouseEvent += (s, e) =>
  1259. {
  1260. // This should not be called because the dialog is modal
  1261. Assert.False (true, "Mouse event should not be captured by the top level when a dialog is modal.");
  1262. };
  1263. Application.Run (top);
  1264. top.Dispose ();
  1265. Application.Shutdown ();
  1266. }
  1267. }