DesktopStyleApplicationLifetimeTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using Avalonia.Controls.ApplicationLifetimes;
  5. using Avalonia.Controls.Platform;
  6. using Avalonia.Platform;
  7. using Avalonia.Rendering;
  8. using Avalonia.Rendering.Composition;
  9. using Avalonia.Threading;
  10. using Avalonia.UnitTests;
  11. using Moq;
  12. using Xunit;
  13. namespace Avalonia.Controls.UnitTests
  14. {
  15. public class DesktopStyleApplicationLifetimeTests
  16. {
  17. IDispatcherImpl CreateDispatcherWithInstantMainLoop()
  18. {
  19. var mock = new Mock<IControlledDispatcherImpl>();
  20. mock.Setup(x => x.RunLoop(It.IsAny<CancellationToken>()))
  21. .Callback(() => Dispatcher.UIThread.ExitAllFrames());
  22. mock.Setup(x => x.CurrentThreadIsLoopThread).Returns(true);
  23. return mock.Object;
  24. }
  25. [Fact]
  26. public void Should_Set_ExitCode_After_Shutdown()
  27. {
  28. using (UnitTestApplication.Start(new TestServices(dispatcherImpl: new ManagedDispatcherImpl(null))))
  29. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  30. {
  31. lifetime.SetupCore(Array.Empty<string>());
  32. Dispatcher.UIThread.Post(() => lifetime.Shutdown(1337));
  33. var exitCode = lifetime.Start(Array.Empty<string>());
  34. Assert.Equal(1337, exitCode);
  35. }
  36. }
  37. [Fact]
  38. public void Should_Close_All_Remaining_Open_Windows_After_Explicit_Exit_Call()
  39. {
  40. using (UnitTestApplication.Start(TestServices.StyledWindow))
  41. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  42. {
  43. lifetime.SetupCore(Array.Empty<string>());
  44. var windows = new List<Window> { new Window(), new Window(), new Window(), new Window() };
  45. foreach (var window in windows)
  46. {
  47. window.Show();
  48. }
  49. Assert.Equal(4, lifetime.Windows.Count);
  50. lifetime.Shutdown();
  51. Assert.Empty(lifetime.Windows);
  52. }
  53. }
  54. [Fact]
  55. public void Should_Only_Exit_On_Explicit_Exit()
  56. {
  57. using (UnitTestApplication.Start(TestServices.StyledWindow))
  58. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  59. {
  60. lifetime.ShutdownMode = ShutdownMode.OnExplicitShutdown;
  61. lifetime.SetupCore(Array.Empty<string>());
  62. var hasExit = false;
  63. lifetime.Exit += (_, _) => hasExit = true;
  64. var windowA = new Window();
  65. windowA.Show();
  66. var windowB = new Window();
  67. windowB.Show();
  68. windowA.Close();
  69. Assert.False(hasExit);
  70. windowB.Close();
  71. Assert.False(hasExit);
  72. lifetime.Shutdown();
  73. Assert.True(hasExit);
  74. }
  75. }
  76. [Fact]
  77. public void Should_Exit_After_MainWindow_Closed()
  78. {
  79. using (UnitTestApplication.Start(TestServices.StyledWindow))
  80. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  81. {
  82. lifetime.ShutdownMode = ShutdownMode.OnMainWindowClose;
  83. lifetime.SetupCore(Array.Empty<string>());
  84. var hasExit = false;
  85. lifetime.Exit += (_, _) => hasExit = true;
  86. var mainWindow = new Window();
  87. mainWindow.Show();
  88. lifetime.MainWindow = mainWindow;
  89. var window = new Window();
  90. window.Show();
  91. mainWindow.Close();
  92. Assert.True(hasExit);
  93. }
  94. }
  95. [Fact]
  96. public void Should_Exit_After_Last_Window_Closed()
  97. {
  98. using (UnitTestApplication.Start(TestServices.StyledWindow))
  99. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  100. {
  101. lifetime.ShutdownMode = ShutdownMode.OnLastWindowClose;
  102. lifetime.SetupCore(Array.Empty<string>());
  103. var hasExit = false;
  104. lifetime.Exit += (_, _) => hasExit = true;
  105. var windowA = new Window();
  106. windowA.Show();
  107. var windowB = new Window();
  108. windowB.Show();
  109. windowA.Close();
  110. Assert.False(hasExit);
  111. windowB.Close();
  112. Assert.True(hasExit);
  113. }
  114. }
  115. [Fact]
  116. public void Show_Should_Add_Window_To_OpenWindows()
  117. {
  118. using (UnitTestApplication.Start(TestServices.StyledWindow))
  119. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  120. {
  121. lifetime.SetupCore(Array.Empty<string>());
  122. var window = new Window();
  123. window.Show();
  124. Assert.Equal(new[] { window }, lifetime.Windows);
  125. }
  126. }
  127. [Fact]
  128. public void Window_Should_Be_Added_To_OpenWindows_Only_Once()
  129. {
  130. using (UnitTestApplication.Start(TestServices.StyledWindow))
  131. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  132. {
  133. lifetime.SetupCore(Array.Empty<string>());
  134. var window = new Window();
  135. window.Show();
  136. window.Show();
  137. window.IsVisible = true;
  138. Assert.Equal(new[] { window }, lifetime.Windows);
  139. window.Close();
  140. }
  141. }
  142. [Fact]
  143. public void Close_Should_Remove_Window_From_OpenWindows()
  144. {
  145. using (UnitTestApplication.Start(TestServices.StyledWindow))
  146. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  147. {
  148. lifetime.SetupCore(Array.Empty<string>());
  149. var window = new Window();
  150. window.Show();
  151. Assert.Equal(1, lifetime.Windows.Count);
  152. window.Close();
  153. Assert.Empty(lifetime.Windows);
  154. }
  155. }
  156. [Fact]
  157. public void Impl_Closing_Should_Remove_Window_From_OpenWindows()
  158. {
  159. var windowImpl = new Mock<IWindowImpl>();
  160. windowImpl.Setup(x => x.Compositor).Returns(RendererMocks.CreateDummyCompositor());
  161. windowImpl.SetupProperty(x => x.Closed);
  162. windowImpl.Setup(x => x.DesktopScaling).Returns(1);
  163. windowImpl.Setup(x => x.RenderScaling).Returns(1);
  164. var services = TestServices.StyledWindow.With(
  165. windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object));
  166. using (UnitTestApplication.Start(services))
  167. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  168. {
  169. lifetime.SetupCore(Array.Empty<string>());
  170. var window = new Window();
  171. window.Show();
  172. Assert.Equal(1, lifetime.Windows.Count);
  173. windowImpl.Object.Closed();
  174. Assert.Empty(lifetime.Windows);
  175. }
  176. }
  177. [Fact]
  178. public void Should_Allow_Canceling_Shutdown_Via_ShutdownRequested_Event()
  179. {
  180. using (UnitTestApplication.Start(TestServices.StyledWindow.With(dispatcherImpl: new ManagedDispatcherImpl(null))))
  181. using (var lifetime = new ClassicDesktopStyleApplicationLifetime())
  182. {
  183. var lifetimeEvents = new Mock<IPlatformLifetimeEventsImpl>();
  184. AvaloniaLocator.CurrentMutable.Bind<IPlatformLifetimeEventsImpl>().ToConstant(lifetimeEvents.Object);
  185. // Force exit immediately
  186. Dispatcher.UIThread.Post(Dispatcher.UIThread.ExitAllFrames);
  187. lifetime.Start(Array.Empty<string>());
  188. var window = new Window();
  189. var raised = 0;
  190. window.Show();
  191. lifetime.ShutdownRequested += (_, e) =>
  192. {
  193. e.Cancel = true;
  194. ++raised;
  195. };
  196. lifetimeEvents.Raise(x => x.ShutdownRequested += null, new ShutdownRequestedEventArgs());
  197. Assert.Equal(1, raised);
  198. Assert.Equal(new[] { window }, lifetime.Windows);
  199. }
  200. }
  201. [Fact]
  202. public void MainWindow_Closed_Shutdown_Should_Be_Cancellable()
  203. {
  204. using (UnitTestApplication.Start(TestServices.StyledWindow))
  205. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  206. {
  207. lifetime.ShutdownMode = ShutdownMode.OnMainWindowClose;
  208. lifetime.SetupCore(Array.Empty<string>());
  209. var hasExit = false;
  210. lifetime.Exit += (_, _) => hasExit = true;
  211. var mainWindow = new Window();
  212. mainWindow.Show();
  213. lifetime.MainWindow = mainWindow;
  214. var window = new Window();
  215. window.Show();
  216. var raised = 0;
  217. lifetime.ShutdownRequested += (_, e) =>
  218. {
  219. e.Cancel = true;
  220. ++raised;
  221. };
  222. mainWindow.Close();
  223. Assert.Equal(1, raised);
  224. Assert.False(hasExit);
  225. }
  226. }
  227. [Fact]
  228. public void LastWindow_Closed_Shutdown_Should_Be_Cancellable()
  229. {
  230. using (UnitTestApplication.Start(TestServices.StyledWindow))
  231. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  232. {
  233. lifetime.ShutdownMode = ShutdownMode.OnLastWindowClose;
  234. lifetime.SetupCore(Array.Empty<string>());
  235. var hasExit = false;
  236. lifetime.Exit += (_, _) => hasExit = true;
  237. var windowA = new Window();
  238. windowA.Show();
  239. var windowB = new Window();
  240. windowB.Show();
  241. var raised = 0;
  242. lifetime.ShutdownRequested += (_, e) =>
  243. {
  244. e.Cancel = true;
  245. ++raised;
  246. };
  247. windowA.Close();
  248. Assert.False(hasExit);
  249. windowB.Close();
  250. Assert.Equal(1, raised);
  251. Assert.False(hasExit);
  252. }
  253. }
  254. [Fact]
  255. public void TryShutdown_Cancellable_By_Preventing_Window_Close()
  256. {
  257. using (UnitTestApplication.Start(TestServices.StyledWindow))
  258. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  259. {
  260. lifetime.SetupCore(Array.Empty<string>());
  261. lifetime.Exit += (_, _) => Assert.Fail("lifetime.Exit was called.");
  262. Dispatcher.UIThread.ShutdownStarted += UiThreadOnShutdownStarted;
  263. static void UiThreadOnShutdownStarted(object sender, EventArgs e)
  264. {
  265. Assert.Fail("Dispatcher.UIThread.ShutdownStarted was called.");
  266. }
  267. var windowA = new Window();
  268. windowA.Show();
  269. var windowB = new Window();
  270. windowB.Show();
  271. var raised = 0;
  272. windowA.Closing += (_, e) =>
  273. {
  274. e.Cancel = true;
  275. ++raised;
  276. };
  277. lifetime.TryShutdown();
  278. Assert.Equal(1, raised);
  279. Dispatcher.UIThread.ShutdownStarted -= UiThreadOnShutdownStarted;
  280. }
  281. }
  282. [Fact]
  283. public void Shutdown_NotCancellable_By_Preventing_Window_Close()
  284. {
  285. using (UnitTestApplication.Start(TestServices.StyledWindow.With(dispatcherImpl: CreateDispatcherWithInstantMainLoop())))
  286. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  287. {
  288. lifetime.SetupCore(Array.Empty<string>());
  289. var hasExit = false;
  290. lifetime.Exit += (_, _) => hasExit = true;
  291. var windowA = new Window();
  292. windowA.Show();
  293. var windowB = new Window();
  294. windowB.Show();
  295. var raised = 0;
  296. windowA.Closing += (_, e) =>
  297. {
  298. e.Cancel = true;
  299. ++raised;
  300. };
  301. lifetime.Shutdown();
  302. Assert.Equal(1, raised);
  303. Assert.True(hasExit);
  304. }
  305. }
  306. [Fact]
  307. public void Shutdown_Doesnt_Raise_Shutdown_Requested()
  308. {
  309. using (UnitTestApplication.Start(TestServices.StyledWindow))
  310. using(var lifetime = new ClassicDesktopStyleApplicationLifetime())
  311. {
  312. lifetime.SetupCore(Array.Empty<string>());
  313. var hasExit = false;
  314. lifetime.Exit += (_, _) => hasExit = true;
  315. var raised = 0;
  316. lifetime.ShutdownRequested += (_, _) =>
  317. {
  318. ++raised;
  319. };
  320. lifetime.Shutdown();
  321. Assert.Equal(0, raised);
  322. Assert.True(hasExit);
  323. }
  324. }
  325. }
  326. }