ShadowTests.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. ๏ปฟusing System.Text;
  2. using UnitTests;
  3. using Xunit.Abstractions;
  4. namespace ViewBaseTests.Adornments;
  5. [Collection ("Global Test Setup")]
  6. public class ShadowTests (ITestOutputHelper output)
  7. {
  8. private readonly ITestOutputHelper _output = output;
  9. [Fact]
  10. public void Default_None ()
  11. {
  12. var view = new View ();
  13. Assert.Equal (ShadowStyle.None, view.ShadowStyle);
  14. Assert.Equal (ShadowStyle.None, view.Margin!.ShadowStyle);
  15. view.Dispose ();
  16. }
  17. [Theory]
  18. [InlineData (ShadowStyle.None)]
  19. [InlineData (ShadowStyle.Opaque)]
  20. [InlineData (ShadowStyle.Transparent)]
  21. public void Set_View_Sets_Margin (ShadowStyle style)
  22. {
  23. var view = new View ();
  24. view.ShadowStyle = style;
  25. Assert.Equal (style, view.ShadowStyle);
  26. Assert.Equal (style, view.Margin!.ShadowStyle);
  27. view.Dispose ();
  28. }
  29. [Theory]
  30. [InlineData (ShadowStyle.None, 0, 0, 0, 0)]
  31. [InlineData (ShadowStyle.Opaque, 0, 0, 1, 1)]
  32. [InlineData (ShadowStyle.Transparent, 0, 0, 1, 1)]
  33. public void ShadowStyle_Margin_Thickness (ShadowStyle style, int expectedLeft, int expectedTop, int expectedRight, int expectedBottom)
  34. {
  35. var superView = new View
  36. {
  37. Height = 10, Width = 10
  38. };
  39. View view = new ()
  40. {
  41. Width = Dim.Auto (),
  42. Height = Dim.Auto (),
  43. Text = "0123",
  44. HighlightStates = MouseState.Pressed,
  45. ShadowStyle = style,
  46. CanFocus = true
  47. };
  48. superView.Add (view);
  49. superView.BeginInit ();
  50. superView.EndInit ();
  51. Assert.Equal (new (expectedLeft, expectedTop, expectedRight, expectedBottom), view.Margin!.Thickness);
  52. }
  53. [Theory]
  54. [InlineData (ShadowStyle.None, 3)]
  55. [InlineData (ShadowStyle.Opaque, 4)]
  56. [InlineData (ShadowStyle.Transparent, 4)]
  57. public void Style_Changes_Margin_Thickness (ShadowStyle style, int expected)
  58. {
  59. var view = new View ();
  60. view.Margin!.Thickness = new (3);
  61. view.ShadowStyle = style;
  62. Assert.Equal (new (3, 3, expected, expected), view.Margin.Thickness);
  63. view.ShadowStyle = ShadowStyle.None;
  64. Assert.Equal (new (3), view.Margin.Thickness);
  65. view.Dispose ();
  66. }
  67. [Theory]
  68. [InlineData (ShadowStyle.None)]
  69. [InlineData (ShadowStyle.Opaque)]
  70. [InlineData (ShadowStyle.Transparent)]
  71. public void ShadowWidth_ShadowHeight_Defaults (ShadowStyle style)
  72. {
  73. View view = new () { ShadowStyle = style };
  74. if (view.ShadowStyle == ShadowStyle.None)
  75. {
  76. Assert.Equal (new (0, 0), view.Margin!.ShadowSize);
  77. }
  78. else
  79. {
  80. Assert.Equal (new (1, 1), view.Margin!.ShadowSize);
  81. }
  82. }
  83. [Fact]
  84. public void ShadowStyle_Opaque_Margin_ShadowWidth_ShadowHeight_Cannot_Be_Set_Different_Of_One ()
  85. {
  86. View view = new () { ShadowStyle = ShadowStyle.Opaque };
  87. view.Margin!.ShadowSize = new (3, 4);
  88. Assert.Equal (1, view.Margin.ShadowSize.Width);
  89. Assert.Equal (1, view.Margin.ShadowSize.Height);
  90. }
  91. [Theory]
  92. [InlineData (ShadowStyle.None, 0)]
  93. [InlineData (ShadowStyle.Opaque, 1)]
  94. [InlineData (ShadowStyle.Transparent, 1)]
  95. public void Margin_ShadowWidth_ShadowHeight_Cannot_Be_Set_Less_Than_Zero (ShadowStyle style, int expectedLength)
  96. {
  97. View view = new () { ShadowStyle = style };
  98. view.Margin!.ShadowSize = new (-1, -1);
  99. Assert.Equal (expectedLength, view.Margin!.ShadowSize.Width);
  100. Assert.Equal (expectedLength, view.Margin!.ShadowSize.Height);
  101. }
  102. [Fact]
  103. public void Changing_ShadowStyle_Correctly_Set_ShadowWidth_ShadowHeight_Thickness ()
  104. {
  105. View view = new () { ShadowStyle = ShadowStyle.Transparent };
  106. view.Margin!.ShadowSize = new (2, 2);
  107. Assert.Equal (new (2, 2), view.Margin!.ShadowSize);
  108. Assert.Equal (new (0, 0, 2, 2), view.Margin.Thickness);
  109. view.ShadowStyle = ShadowStyle.None;
  110. Assert.Equal (new (2, 2), view.Margin!.ShadowSize);
  111. Assert.Equal (new (0, 0, 0, 0), view.Margin.Thickness);
  112. view.ShadowStyle = ShadowStyle.Opaque;
  113. Assert.Equal (new (1, 1), view.Margin!.ShadowSize);
  114. Assert.Equal (new (0, 0, 1, 1), view.Margin.Thickness);
  115. }
  116. [Theory]
  117. [InlineData (ShadowStyle.None, 2, 1, 3, 0, 0, 0)]
  118. [InlineData (ShadowStyle.Opaque, 1, 1, 1, 1, 1, 1)]
  119. [InlineData (ShadowStyle.Transparent, 2, 1, 3, 2, 2, 3)]
  120. public void Changing_ShadowWidth_ShadowHeight_Correctly_Set_Thickness (
  121. ShadowStyle style,
  122. int expectedLength1,
  123. int expectedLength2,
  124. int expectedLength3,
  125. int expectedThickness1,
  126. int expectedThickness2,
  127. int expectedThickness3
  128. )
  129. {
  130. View view = new () { ShadowStyle = style };
  131. view.Margin!.ShadowSize = new (2, 2);
  132. Assert.Equal (expectedLength1, view.Margin!.ShadowSize.Width);
  133. Assert.Equal (expectedLength1, view.Margin.ShadowSize.Height);
  134. Assert.Equal (new (0, 0, expectedThickness1, expectedThickness1), view.Margin.Thickness);
  135. view.Margin!.ShadowSize = new (1, 1);
  136. Assert.Equal (expectedLength2, view.Margin!.ShadowSize.Width);
  137. Assert.Equal (expectedLength2, view.Margin.ShadowSize.Height);
  138. Assert.Equal (new (0, 0, expectedThickness2, expectedThickness2), view.Margin.Thickness);
  139. view.Margin!.ShadowSize = new (3, 3);
  140. Assert.Equal (expectedLength3, view.Margin!.ShadowSize.Width);
  141. Assert.Equal (expectedLength3, view.Margin.ShadowSize.Height);
  142. Assert.Equal (new (0, 0, expectedThickness3, expectedThickness3), view.Margin.Thickness);
  143. view.ShadowStyle = ShadowStyle.None;
  144. Assert.Equal (expectedLength3, view.Margin!.ShadowSize.Width);
  145. Assert.Equal (expectedLength3, view.Margin.ShadowSize.Height);
  146. Assert.Equal (new (0, 0, 0, 0), view.Margin.Thickness);
  147. }
  148. [Theory]
  149. [InlineData (ShadowStyle.None, 0, 1)]
  150. [InlineData (ShadowStyle.Opaque, 1, 1)]
  151. [InlineData (ShadowStyle.Transparent, 1, 1)]
  152. public void Changing_Thickness_Correctly_Set_Thickness (ShadowStyle style, int expectedLength, int expectedThickness)
  153. {
  154. View view = new () { ShadowStyle = style };
  155. Assert.Equal (new (0, 0, expectedLength, expectedLength), view.Margin!.Thickness);
  156. view.Margin!.Thickness = new (0, 0, 1, 1);
  157. Assert.Equal (expectedLength, view.Margin!.ShadowSize.Width);
  158. Assert.Equal (expectedLength, view.Margin.ShadowSize.Height);
  159. Assert.Equal (new (0, 0, expectedThickness, expectedThickness), view.Margin.Thickness);
  160. }
  161. [Fact]
  162. public void ShadowStyle_Transparent_Handles_Wide_Glyphs_Correctly ()
  163. {
  164. IApplication app = Application.Create ();
  165. app.Init ("fake");
  166. app.Driver?.SetScreenSize (6, 5);
  167. // Using a replacement char to make sure wide glyphs are handled correctly
  168. // in the shadow area, to not confusing with a space char.
  169. app.Driver?.GetOutputBuffer ().SetWideGlyphReplacement (Rune.ReplacementChar);
  170. Runnable superview = new () { Width = Dim.Fill (), Height = Dim.Fill () };
  171. superview.Text = """
  172. ๐ŸŽ๐ŸŽ๐ŸŽ
  173. ๐ŸŽ๐ŸŽ๐ŸŽ
  174. ๐ŸŽ๐ŸŽ๐ŸŽ
  175. ๐ŸŽ๐ŸŽ๐ŸŽ
  176. ๐ŸŽ๐ŸŽ๐ŸŽ
  177. """;
  178. View view = new () { Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single, ShadowStyle = ShadowStyle.Transparent };
  179. view.Margin!.ShadowSize = view.Margin!.ShadowSize with { Width = 2 };
  180. superview.Add (view);
  181. app.Begin (superview);
  182. Assert.Equal (new (2, 1), view.Margin!.ShadowSize);
  183. Assert.Equal (new (0, 0, 2, 1), view.Margin!.Thickness);
  184. DriverAssert.AssertDriverContentsAre (
  185. """
  186. โ”Œโ”€โ”€โ”๐ŸŽ
  187. โ”‚ โ”‚๐ŸŽ
  188. โ”‚ โ”‚๐ŸŽ
  189. โ””โ”€โ”€โ”˜๐ŸŽ
  190. ๏ฟฝ ๐ŸŽ๐ŸŽ
  191. """,
  192. _output,
  193. app.Driver);
  194. view.Margin!.ShadowSize = new (1, 2);
  195. app.LayoutAndDraw ();
  196. Assert.Equal (new (1, 2), view.Margin!.ShadowSize);
  197. Assert.Equal (new (0, 0, 2, 2), view.Margin!.Thickness);
  198. DriverAssert.AssertDriverContentsAre (
  199. """
  200. โ”Œโ”€โ”€โ”๐ŸŽ
  201. โ”‚ โ”‚๏ฟฝ
  202. โ””โ”€โ”€โ”˜๏ฟฝ
  203. ๏ฟฝ ๐ŸŽ๐ŸŽ
  204. ๏ฟฝ ๐ŸŽ๐ŸŽ
  205. """,
  206. _output,
  207. app.Driver);
  208. view.Width = Dim.Fill (1);
  209. app.LayoutAndDraw ();
  210. Assert.Equal (new (1, 2), view.Margin!.ShadowSize);
  211. Assert.Equal (new (0, 0, 2, 2), view.Margin!.Thickness);
  212. DriverAssert.AssertDriverContentsAre (
  213. """
  214. โ”Œโ”€โ” ๐ŸŽ
  215. โ”‚ โ”‚ ๏ฟฝ
  216. โ””โ”€โ”˜ ๏ฟฝ
  217. ๏ฟฝ ๐ŸŽ๏ฟฝ
  218. ๏ฟฝ ๐ŸŽ๏ฟฝ
  219. """,
  220. _output,
  221. app.Driver);
  222. }
  223. [Fact]
  224. public void ShadowStyle_Opaque_Change_Thickness_On_Mouse_Pressed_Released ()
  225. {
  226. IApplication app = Application.Create ();
  227. app.Init ("fake");
  228. app.Driver?.SetScreenSize (10, 4);
  229. Runnable superview = new () { Width = Dim.Fill (), Height = Dim.Fill () };
  230. View view = new () { Width = 7, Height = 2, ShadowStyle = ShadowStyle.Opaque, Text = "| Hi |", HighlightStates = MouseState.Pressed };
  231. superview.Add (view);
  232. app.Begin (superview);
  233. DriverAssert.AssertDriverContentsAre (
  234. """
  235. | Hi |โ––
  236. โ–โ–€โ–€โ–€โ–€โ–€โ–˜
  237. """,
  238. _output,
  239. app.Driver);
  240. app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (2, 0), Flags = MouseFlags.Button1Pressed });
  241. app.LayoutAndDraw ();
  242. DriverAssert.AssertDriverContentsAre (
  243. """
  244. | Hi |
  245. """,
  246. _output,
  247. app.Driver);
  248. app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (2, 0), Flags = MouseFlags.Button1Released });
  249. app.LayoutAndDraw ();
  250. DriverAssert.AssertDriverContentsAre (
  251. """
  252. | Hi |โ––
  253. โ–โ–€โ–€โ–€โ–€โ–€โ–˜
  254. """,
  255. _output,
  256. app.Driver);
  257. }
  258. [Fact]
  259. public void ShadowStyle_Transparent_Never_Throws_Navigating_Outside_Bounds ()
  260. {
  261. IApplication app = Application.Create ();
  262. app.Init ("fake");
  263. app.Driver?.SetScreenSize (6, 5);
  264. Runnable superview = new () { Width = Dim.Fill (), Height = Dim.Fill () };
  265. superview.Text = """
  266. ๐ŸŽ๐ŸŽ๐ŸŽ
  267. ๐ŸŽ๐ŸŽ๐ŸŽ
  268. ๐ŸŽ๐ŸŽ๐ŸŽ
  269. ๐ŸŽ๐ŸŽ๐ŸŽ
  270. ๐ŸŽ๐ŸŽ๐ŸŽ
  271. """;
  272. View view = new ()
  273. {
  274. Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single, ShadowStyle = ShadowStyle.Transparent,
  275. Arrangement = ViewArrangement.Movable, CanFocus = true
  276. };
  277. view.Margin!.ShadowSize = view.Margin!.ShadowSize with { Width = 2 };
  278. superview.Add (view);
  279. app.Begin (superview);
  280. Assert.Equal (new (0, 0), view.Frame.Location);
  281. Assert.True (app.Keyboard.RaiseKeyDownEvent (Key.F5.WithCtrl));
  282. int i = 0;
  283. DecrementValue (-10, Key.CursorLeft);
  284. Assert.Equal (-10, i);
  285. IncrementValue (0, Key.CursorRight);
  286. Assert.Equal (0, i);
  287. DecrementValue (-10, Key.CursorUp);
  288. Assert.Equal (-10, i);
  289. IncrementValue (20, Key.CursorDown);
  290. Assert.Equal (20, i);
  291. DecrementValue (0, Key.CursorUp);
  292. Assert.Equal (0, i);
  293. IncrementValue (20, Key.CursorRight);
  294. Assert.Equal (20, i);
  295. return;
  296. void DecrementValue (int count, Key key)
  297. {
  298. for (; i > count; i--)
  299. {
  300. Assert.True (app.Keyboard.RaiseKeyDownEvent (key));
  301. app.LayoutAndDraw ();
  302. CheckAssertion (new (i - 1, 0), new (0, i - 1), key);
  303. }
  304. }
  305. void IncrementValue (int count, Key key)
  306. {
  307. for (; i < count; i++)
  308. {
  309. Assert.True (app.Keyboard.RaiseKeyDownEvent (key));
  310. app.LayoutAndDraw ();
  311. CheckAssertion (new (i + 1, 0), new (0, i + 1), key);
  312. }
  313. }
  314. bool? IsColumn (Key key)
  315. {
  316. if (key == Key.CursorLeft || key == Key.CursorRight)
  317. {
  318. return true;
  319. }
  320. if (key == Key.CursorUp || key == Key.CursorDown)
  321. {
  322. return false;
  323. }
  324. return null;
  325. }
  326. void CheckAssertion (Point colLocation, Point rowLocation, Key key)
  327. {
  328. bool? isCol = IsColumn (key);
  329. switch (isCol)
  330. {
  331. case true:
  332. Assert.Equal (colLocation, view.Frame.Location);
  333. break;
  334. case false:
  335. Assert.Equal (rowLocation, view.Frame.Location);
  336. break;
  337. default:
  338. throw new InvalidOperationException ();
  339. }
  340. }
  341. }
  342. [Theory]
  343. [InlineData (ShadowStyle.None, 3, 4, 4)]
  344. [InlineData (ShadowStyle.Opaque, 4, 5, 4)]
  345. [InlineData (ShadowStyle.Transparent, 4, 5, 4)]
  346. public void Margin_Thickness_Changes_Adjust_Correctly (ShadowStyle style, int expectedThickness, int expectedThicknessAdjust, int expectedThicknessNone)
  347. {
  348. var view = new View ();
  349. view.Margin!.Thickness = new (3);
  350. view.ShadowStyle = style;
  351. Assert.Equal (new (3, 3, expectedThickness, expectedThickness), view.Margin.Thickness);
  352. view.Margin.Thickness = new (3, 3, expectedThickness + 1, expectedThickness + 1);
  353. Assert.Equal (new (3, 3, expectedThicknessAdjust, expectedThicknessAdjust), view.Margin.Thickness);
  354. view.ShadowStyle = ShadowStyle.None;
  355. Assert.Equal (new (3, 3, expectedThicknessNone, expectedThicknessNone), view.Margin.Thickness);
  356. view.Dispose ();
  357. }
  358. [Fact]
  359. public void Runnable_View_Overlap_Other_Runnables ()
  360. {
  361. IApplication app = Application.Create ();
  362. app.Init ("fake");
  363. app.Driver?.SetScreenSize (10, 5);
  364. Runnable superview = new () { Width = Dim.Fill (), Height = Dim.Fill (), Text = "๐ŸŽ".Repeat (25)! };
  365. View view = new () { Width = 7, Height = 2, ShadowStyle = ShadowStyle.Opaque, Text = "| Hi |" };
  366. superview.Add (view);
  367. app.Begin (superview);
  368. DriverAssert.AssertDriverContentsAre (
  369. """
  370. | Hi |โ–– ๐ŸŽ
  371. โ–โ–€โ–€โ–€โ–€โ–€โ–˜ ๐ŸŽ
  372. ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ
  373. ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ
  374. ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ
  375. """,
  376. _output,
  377. app.Driver);
  378. Runnable modalSuperview = new () { Y = 1, Width = Dim.Fill (), Height = 4, BorderStyle = LineStyle.Single };
  379. View view1 = new () { Width = 8, Height = 2, ShadowStyle = ShadowStyle.Opaque, Text = "| Hey |" };
  380. modalSuperview.Add (view1);
  381. app.Begin (modalSuperview);
  382. Assert.True (modalSuperview.IsModal);
  383. DriverAssert.AssertDriverContentsAre (
  384. """
  385. | Hi |โ–– ๐ŸŽ
  386. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  387. โ”‚| Hey |โ––โ”‚
  388. โ”‚โ–โ–€โ–€โ–€โ–€โ–€โ–€โ–˜โ”‚
  389. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  390. """,
  391. _output,
  392. app.Driver);
  393. app.Dispose ();
  394. }
  395. [Fact]
  396. public void TransparentShadow_Draws_Transparent_At_Driver_Output ()
  397. {
  398. // Arrange
  399. using IApplication app = Application.Create ();
  400. app.Init ("fake");
  401. app.Driver!.SetScreenSize (2, 1);
  402. app.Driver.Force16Colors = true;
  403. using Runnable superView = new ();
  404. superView.Width = Dim.Fill ();
  405. superView.Height = Dim.Fill ();
  406. superView.Text = "AB";
  407. superView.TextFormatter.WordWrap = true;
  408. superView.SetScheme (new (new Attribute (Color.Black, Color.White)));
  409. // Create view with transparent shadow
  410. View viewWithShadow = new ()
  411. {
  412. Width = Dim.Auto (),
  413. Height = Dim.Auto (),
  414. Text = "*",
  415. ShadowStyle = ShadowStyle.Transparent
  416. };
  417. // Make it so the margin is only on the right for simplicity
  418. viewWithShadow.Margin!.Thickness = new (0, 0, 1, 0);
  419. viewWithShadow.SetScheme (new (new Attribute (Color.Black, Color.White)));
  420. superView.Add (viewWithShadow);
  421. // Act
  422. app.Begin (superView);
  423. app.LayoutAndDraw ();
  424. app.Driver.Refresh ();
  425. // Assert
  426. Assert.Equal (new (0, 0, 2, 2), viewWithShadow.Frame);
  427. Assert.Equal (new (0, 0, 1, 1), viewWithShadow.Viewport);
  428. _output.WriteLine ("Actual driver contents:");
  429. _output.WriteLine (app.Driver.ToString ());
  430. _output.WriteLine ("\nActual driver output:");
  431. string? output = app.Driver.GetOutput ().GetLastOutput ();
  432. _output.WriteLine (output);
  433. // Printed with bright black (dark gray) text on bright black (dark gray) background making it invisible
  434. DriverAssert.AssertDriverOutputIs ("""
  435. \x1b[30m\x1b[107m*\x1b[90m\x1b[100mB
  436. """, _output, app.Driver);
  437. }
  438. [Fact]
  439. public void TransparentShadow_OverWide_Draws_Transparent_At_Driver_Output ()
  440. {
  441. // Arrange
  442. using IApplication app = Application.Create ();
  443. app.Init ("fake");
  444. app.Driver!.SetScreenSize (2, 3);
  445. app.Driver.Force16Colors = true;
  446. using Runnable superView = new ();
  447. superView.Width = Dim.Fill ();
  448. superView.Height = Dim.Fill ();
  449. superView.Text = "๐ŸŽ๐ŸŽ๐ŸŽ๐ŸŽ";
  450. superView.TextFormatter.WordWrap = true;
  451. superView.SetScheme (new (new Attribute (Color.Black, Color.White)));
  452. // Create view with transparent shadow
  453. View viewWithShadow = new ()
  454. {
  455. Width = Dim.Auto (),
  456. Height = Dim.Auto (),
  457. Text = "*",
  458. ShadowStyle = ShadowStyle.Transparent
  459. };
  460. // Make it so the margin is only on the bottom for simplicity
  461. viewWithShadow.Margin!.Thickness = new (0, 0, 0, 1);
  462. viewWithShadow.SetScheme (new (new Attribute (Color.Black, Color.White)));
  463. superView.Add (viewWithShadow);
  464. // Act
  465. app.Begin (superView);
  466. app.LayoutAndDraw ();
  467. app.Driver.Refresh ();
  468. // Assert
  469. _output.WriteLine ("Actual driver contents:");
  470. _output.WriteLine (app.Driver.ToString ());
  471. _output.WriteLine ("\nActual driver output:");
  472. string? output = app.Driver.GetOutput ().GetLastOutput ();
  473. _output.WriteLine (output);
  474. DriverAssert.AssertDriverOutputIs ("""
  475. \x1b[30m\x1b[107m*\x1b[90m\x1b[103m \x1b[97m\x1b[40m \x1b[90m\x1b[100m \x1b[97m\x1b[40m๐ŸŽ
  476. """, _output, app.Driver);
  477. }
  478. }