FakeDriverTests.cs 15 KB

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