FakeDriverTests.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. using System.Text;
  2. using Xunit.Abstractions;
  3. namespace UnitTests.DriverTests;
  4. /// <summary>
  5. /// Tests for the FakeDriver to ensure it works properly with the modern component factory architecture.
  6. /// </summary>
  7. public class FakeDriverTests (ITestOutputHelper output)
  8. {
  9. private readonly ITestOutputHelper _output = output;
  10. #region Basic FakeDriver Tests
  11. [Fact]
  12. [AutoInitShutdown]
  13. public void FakeDriver_Init_Works ()
  14. {
  15. // Verify Application was initialized
  16. Assert.True (Application.Initialized);
  17. // Assert.NotNull (Application.Top);
  18. // Verify it's using a driver facade (modern architecture)
  19. Assert.IsAssignableFrom<IConsoleDriverFacade> (Application.Driver);
  20. _output.WriteLine ($"Driver type: {Application.Driver.GetType ().Name}");
  21. _output.WriteLine ($"Screen size: {Application.Screen}");
  22. }
  23. [Fact]
  24. [AutoInitShutdown]
  25. public void FakeDriver_Screen_Has_Default_Size ()
  26. {
  27. // Default size should be 80x25
  28. Assert.Equal (new (0, 0, 80, 25), Application.Screen);
  29. Assert.Equal (80, Application.Driver!.Cols);
  30. Assert.Equal (25, Application.Driver.Rows);
  31. }
  32. [Fact]
  33. [AutoInitShutdown]
  34. public void FakeDriver_Can_Resize ()
  35. {
  36. // Start with default size
  37. Assert.Equal (80, Application.Driver!.Cols);
  38. Assert.Equal (25, Application.Driver.Rows);
  39. // Resize to 100x30
  40. Application.Driver?.SetScreenSize (100, 30);
  41. // Verify new size
  42. Assert.Equal (100, Application.Driver.Cols);
  43. Assert.Equal (30, Application.Driver.Rows);
  44. Assert.Equal (new (0, 0, 100, 30), Application.Screen);
  45. }
  46. [Fact]
  47. [AutoInitShutdown]
  48. public void FakeDriver_Top_Is_Created ()
  49. {
  50. Application.Top = new ();
  51. Application.Begin (Application.Top);
  52. Assert.NotNull (Application.Top);
  53. Assert.True (Application.Top.IsInitialized);
  54. Assert.Equal (new (0, 0, 80, 25), Application.Top.Frame);
  55. }
  56. [Fact]
  57. [AutoInitShutdown]
  58. public void FakeDriver_Can_Add_View_To_Top ()
  59. {
  60. Application.Top = new ();
  61. var label = new Label { Text = "Hello World" };
  62. Application.Top!.Add (label);
  63. Assert.Contains (label, Application.Top!.SubViews);
  64. Assert.Same (Application.Top, label.SuperView);
  65. }
  66. [Fact]
  67. [AutoInitShutdown]
  68. public void FakeDriver_RunIteration_Works ()
  69. {
  70. Application.Top = new ();
  71. var label = new Label { Text = "Hello" };
  72. Application.Top!.Add (label);
  73. Application.Begin (Application.Top);
  74. // Run a single iteration - this should layout and draw
  75. AutoInitShutdownAttribute.RunIteration ();
  76. // Verify the view was laid out
  77. Assert.True (label.Frame.Width > 0);
  78. Assert.True (label.IsInitialized);
  79. }
  80. #endregion
  81. #region AutoInitShutdown Attribute Tests
  82. //[Theory]
  83. //[InlineData (true)]
  84. //[InlineData (false)]
  85. //public void AutoInitShutdown_Attribute_Respects_AutoInit_Parameter (bool autoInit)
  86. //{
  87. // // When autoInit is false, Application should not be initialized
  88. // // When autoInit is true, Application should be initialized
  89. // // This test will be called twice - once with autoInit=true, once with false
  90. // // We can't use the attribute directly in the test body, but we can verify
  91. // // the behavior by checking Application.Initialized
  92. // // For this test to work properly, we need to call Application.Init manually when autoInit=false
  93. // bool wasInitialized = Application.Initialized;
  94. // try
  95. // {
  96. // if (!wasInitialized)
  97. // {
  98. // Application.ResetState ();
  99. // var fa = new FakeApplicationFactory ();
  100. // using IDisposable cleanup = fa.SetupFakeApplication ();
  101. // Assert.True (Application.Initialized);
  102. // }
  103. // else
  104. // {
  105. // Assert.True (Application.Initialized);
  106. // }
  107. // }
  108. // finally
  109. // {
  110. // if (!wasInitialized)
  111. // {
  112. // Application.Shutdown ();
  113. // }
  114. // }
  115. //}
  116. [Fact]
  117. public void Without_AutoInitShutdown_Application_Is_Not_Initialized ()
  118. {
  119. // This test deliberately does NOT use [AutoInitShutdown]
  120. // Application should not be initialized
  121. Assert.False (Application.Initialized);
  122. Assert.Null (Application.Driver);
  123. Assert.Null (Application.Top);
  124. }
  125. [Fact]
  126. [AutoInitShutdown]
  127. public void AutoInitShutdown_Cleans_Up_After_Test ()
  128. {
  129. // This test verifies that Application is properly initialized
  130. // The After method of AutoInitShutdown will verify cleanup
  131. Assert.True (Application.Initialized);
  132. Assert.NotNull (Application.Driver);
  133. }
  134. #endregion
  135. #region SetupFakeDriver Attribute Tests
  136. [Fact]
  137. [SetupFakeDriver]
  138. public void SetupFakeDriver_Initializes_Driver_With_25x25 ()
  139. {
  140. Assert.NotNull (Application.Driver);
  141. Assert.Equal (new (0, 0, 25, 25), Application.Screen);
  142. Assert.Equal (25, Application.Driver.Cols);
  143. Assert.Equal (25, Application.Driver.Rows);
  144. }
  145. [Fact]
  146. [SetupFakeDriver]
  147. public void SetupFakeDriver_Driver_Is_IConsoleDriver ()
  148. {
  149. Assert.NotNull (Application.Driver);
  150. // Should be IConsoleDriver
  151. Assert.IsAssignableFrom<IConsoleDriver> (Application.Driver);
  152. _output.WriteLine ($"Driver type: {Application.Driver.GetType ().Name}");
  153. }
  154. [Fact]
  155. [SetupFakeDriver]
  156. public void SetupFakeDriver_Can_Set_Screen_Size ()
  157. {
  158. IConsoleDriver fakeDriver = Application.Driver;
  159. Assert.NotNull (fakeDriver);
  160. fakeDriver!.SetScreenSize (100, 50);
  161. Assert.Equal (100, Application.Driver!.Cols);
  162. Assert.Equal (50, Application.Driver.Rows);
  163. }
  164. #endregion
  165. #region Integration Tests
  166. [Fact]
  167. [AutoInitShutdown]
  168. public void FakeDriver_Can_Draw_Simple_View ()
  169. {
  170. Application.Top = new ();
  171. var window = new Window
  172. {
  173. Title = "Test Window",
  174. X = 0,
  175. Y = 0,
  176. Width = 40,
  177. Height = 10
  178. };
  179. var label = new Label
  180. {
  181. Text = "Hello World",
  182. X = 1,
  183. Y = 1
  184. };
  185. window.Add (label);
  186. Application.Top!.Add (window);
  187. Application.Begin (Application.Top);
  188. // Run iteration to layout and draw
  189. AutoInitShutdownAttribute.RunIteration ();
  190. // Verify views were initialized and laid out
  191. Assert.True (window.IsInitialized);
  192. Assert.True (label.IsInitialized);
  193. Assert.True (window.Frame.Width > 0);
  194. Assert.True (label.Frame.Width > 0);
  195. }
  196. [Fact]
  197. [AutoInitShutdown]
  198. public void FakeDriver_Multiple_RunIterations_Work ()
  199. {
  200. Application.Top = new ();
  201. var label = new Label { Text = "Iteration Test" };
  202. Application.Top!.Add (label);
  203. // Run multiple iterations
  204. for (var i = 0; i < 5; i++)
  205. {
  206. AutoInitShutdownAttribute.RunIteration ();
  207. }
  208. Application.Begin (Application.Top);
  209. // Should still be working
  210. Assert.True (Application.Initialized);
  211. Assert.True (label.IsInitialized);
  212. }
  213. [Fact]
  214. [AutoInitShutdown]
  215. public void FakeDriver_Resize_Triggers_Layout ()
  216. {
  217. Application.Top = new ();
  218. var view = new View
  219. {
  220. Width = Dim.Fill (),
  221. Height = Dim.Fill ()
  222. };
  223. Application.Top!.Add (view);
  224. Application.Begin (Application.Top);
  225. AutoInitShutdownAttribute.RunIteration ();
  226. // Check initial size
  227. Rectangle initialFrame = view.Frame;
  228. Assert.Equal (80, initialFrame.Width);
  229. Assert.Equal (25, initialFrame.Height);
  230. // Resize
  231. Application.Driver?.SetScreenSize (100, 40);
  232. // Check new size
  233. Assert.Equal (100, view.Frame.Width);
  234. Assert.Equal (40, view.Frame.Height);
  235. }
  236. [Fact]
  237. [AutoInitShutdown]
  238. public void FakeDriver_Window_Can_Be_Shown_And_Closed ()
  239. {
  240. Application.Top = new ();
  241. var window = new Window { Title = "Test" };
  242. Application.Top!.Add (window);
  243. Application.Begin (Application.Top);
  244. AutoInitShutdownAttribute.RunIteration ();
  245. Assert.True (window.IsInitialized);
  246. Assert.Contains (window, Application.Top!.SubViews);
  247. // Remove window
  248. Application.Top.Remove (window);
  249. AutoInitShutdownAttribute.RunIteration ();
  250. Assert.DoesNotContain (window, Application.Top!.SubViews);
  251. }
  252. #endregion
  253. #region Clipboard Tests
  254. [Fact]
  255. [AutoInitShutdown (useFakeClipboard: true)]
  256. public void FakeDriver_Clipboard_Works_When_Enabled ()
  257. {
  258. Assert.NotNull (Application.Driver!.Clipboard);
  259. Assert.True (Application.Driver.Clipboard.IsSupported);
  260. // Set clipboard content
  261. Application.Driver.Clipboard.SetClipboardData ("Test content");
  262. // Get clipboard content
  263. string content = Application.Driver.Clipboard.GetClipboardData ();
  264. Assert.Equal ("Test content", content);
  265. }
  266. [Fact]
  267. [AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
  268. public void FakeDriver_Clipboard_Can_Throw_NotSupportedException ()
  269. {
  270. Assert.NotNull (Application.Driver!.Clipboard);
  271. // Should throw NotSupportedException
  272. Assert.Throws<NotSupportedException> (() =>
  273. Application.Driver.Clipboard.GetClipboardData ());
  274. }
  275. #endregion
  276. #region Error Handling Tests
  277. [Fact]
  278. [AutoInitShutdown]
  279. public void FakeDriver_Handles_Invalid_Coordinates_Gracefully ()
  280. {
  281. Application.Top = new ();
  282. // Try to add a view with invalid coordinates - should not crash
  283. var view = new View
  284. {
  285. X = -1000,
  286. Y = -1000,
  287. Width = 10,
  288. Height = 10
  289. };
  290. Application.Top!.Add (view);
  291. // Should not throw
  292. AutoInitShutdownAttribute.RunIteration ();
  293. Assert.True (Application.Initialized);
  294. }
  295. [Fact]
  296. [AutoInitShutdown]
  297. public void FakeDriver_Survives_Rapid_Resizes ()
  298. {
  299. Size [] sizes = new []
  300. {
  301. new Size (80, 25),
  302. new Size (100, 30),
  303. new Size (60, 20),
  304. new Size (120, 40),
  305. new Size (80, 25)
  306. };
  307. foreach (Size size in sizes)
  308. {
  309. Application.Driver!.SetScreenSize (size.Width, size.Height);
  310. AutoInitShutdownAttribute.RunIteration ();
  311. Assert.Equal (size.Width, Application.Driver!.Cols);
  312. Assert.Equal (size.Height, Application.Driver.Rows);
  313. }
  314. }
  315. #endregion
  316. #region Buffer and Fill Tests
  317. [Fact]
  318. [AutoInitShutdown]
  319. public void FakeDriver_Can_Fill_Rectangle ()
  320. {
  321. // Verify driver is initialized with buffers
  322. Assert.NotNull (Application.Driver);
  323. Assert.NotNull (Application.Driver!.Contents);
  324. // Fill a rectangle
  325. var rect = new Rectangle (5, 5, 10, 5);
  326. Application.Driver.FillRect (rect, (Rune)'X');
  327. // Verify the rectangle was filled
  328. for (int row = rect.Y; row < rect.Y + rect.Height; row++)
  329. {
  330. for (int col = rect.X; col < rect.X + rect.Width; col++)
  331. {
  332. Assert.Equal ((Rune)'X', Application.Driver.Contents [row, col].Rune);
  333. }
  334. }
  335. }
  336. [Fact]
  337. [AutoInitShutdown]
  338. public void FakeDriver_Buffer_Integrity_After_Multiple_Resizes ()
  339. {
  340. // Start with default size
  341. Assert.Equal (80, Application.Driver!.Cols);
  342. Assert.Equal (25, Application.Driver.Rows);
  343. // Fill with a pattern
  344. Application.Driver.FillRect (new (0, 0, 10, 5), (Rune)'A');
  345. // Resize
  346. Application.Driver?.SetScreenSize (100, 30);
  347. // Verify new size
  348. Assert.Equal (100, Application.Driver.Cols);
  349. Assert.Equal (30, Application.Driver.Rows);
  350. // Verify buffer is clean (no stale runes from previous size)
  351. Assert.NotNull (Application.Driver.Contents);
  352. Assert.Equal (30, Application.Driver.Contents!.GetLength (0));
  353. Assert.Equal (100, Application.Driver.Contents.GetLength (1));
  354. // Fill with new pattern
  355. Application.Driver.FillRect (new (0, 0, 20, 10), (Rune)'B');
  356. // Resize back
  357. Application.Driver?.SetScreenSize (80, 25);
  358. // Verify size is back
  359. Assert.Equal (80, Application.Driver.Cols);
  360. Assert.Equal (25, Application.Driver.Rows);
  361. // Verify buffer dimensions match
  362. Assert.Equal (25, Application.Driver.Contents.GetLength (0));
  363. Assert.Equal (80, Application.Driver.Contents.GetLength (1));
  364. }
  365. #endregion
  366. #region ScreenChanged Event Tests
  367. [Fact]
  368. [AutoInitShutdown]
  369. public void ScreenChanged_Event_Fires_On_SetScreenSize ()
  370. {
  371. var screenChangedFired = false;
  372. Size? newSize = null;
  373. Application.Driver!.SizeChanged += (sender, args) =>
  374. {
  375. screenChangedFired = true;
  376. newSize = args.Size;
  377. };
  378. // Trigger resize using FakeResize which uses SetScreenSize internally
  379. Application.Driver?.SetScreenSize (100, 30);
  380. // Verify event fired
  381. Assert.True (screenChangedFired);
  382. Assert.NotNull (newSize);
  383. Assert.Equal (100, newSize!.Value.Width);
  384. Assert.Equal (30, newSize.Value.Height);
  385. }
  386. [Fact]
  387. [AutoInitShutdown]
  388. public void FakeResize_Triggers_ScreenChanged_And_Updates_Application_Screen ()
  389. {
  390. var screenChangedFired = false;
  391. Size? eventSize = null;
  392. Application.Driver!.SizeChanged += (sender, args) =>
  393. {
  394. screenChangedFired = true;
  395. eventSize = args.Size;
  396. };
  397. // Use FakeResize helper
  398. Application.Driver?.SetScreenSize (120, 40);
  399. // Verify event fired
  400. Assert.True (screenChangedFired);
  401. Assert.NotNull (eventSize);
  402. Assert.Equal (120, eventSize!.Value.Width);
  403. Assert.Equal (40, eventSize.Value.Height);
  404. // Verify Application.Screen was updated
  405. Assert.Equal (new (0, 0, 120, 40), Application.Screen);
  406. Assert.Equal (120, Application.Driver.Cols);
  407. Assert.Equal (40, Application.Driver.Rows);
  408. }
  409. [Fact]
  410. [AutoInitShutdown]
  411. public void SizeChanged_Event_Still_Fires_For_Compatibility ()
  412. {
  413. var sizeChangedFired = false;
  414. var screenChangedFired = false;
  415. #pragma warning disable CS0618 // Type or member is obsolete
  416. Application.Driver!.SizeChanged += (sender, args) => { sizeChangedFired = true; };
  417. #pragma warning restore CS0618 // Type or member is obsolete
  418. Application.Driver.SizeChanged += (sender, args) => { screenChangedFired = true; };
  419. // Trigger resize using FakeResize
  420. Application.Driver?.SetScreenSize (90, 35);
  421. // Both events should fire for compatibility
  422. Assert.True (sizeChangedFired);
  423. Assert.True (screenChangedFired);
  424. }
  425. #endregion
  426. }