TopLevelTests.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using Avalonia.Controls.Presenters;
  5. using Avalonia.Controls.Templates;
  6. using Avalonia.Input;
  7. using Avalonia.Input.Raw;
  8. using Avalonia.Layout;
  9. using Avalonia.LogicalTree;
  10. using Avalonia.Platform;
  11. using Avalonia.UnitTests;
  12. using Moq;
  13. using Xunit;
  14. namespace Avalonia.Controls.UnitTests
  15. {
  16. public class TopLevelTests
  17. {
  18. [Fact]
  19. public void IsAttachedToLogicalTree_Is_True()
  20. {
  21. using (UnitTestApplication.Start(TestServices.StyledWindow))
  22. {
  23. var impl = new Mock<ITopLevelImpl>();
  24. var target = new TestTopLevel(impl.Object);
  25. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  26. }
  27. }
  28. [Fact]
  29. public void ClientSize_Should_Be_Set_On_Construction()
  30. {
  31. using (UnitTestApplication.Start(TestServices.StyledWindow))
  32. {
  33. var impl = new Mock<ITopLevelImpl>();
  34. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  35. var target = new TestTopLevel(impl.Object);
  36. Assert.Equal(new Size(123, 456), target.ClientSize);
  37. }
  38. }
  39. [Fact]
  40. public void Width_Should_Not_Be_Set_On_Construction()
  41. {
  42. using (UnitTestApplication.Start(TestServices.StyledWindow))
  43. {
  44. var impl = new Mock<ITopLevelImpl>();
  45. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  46. var target = new TestTopLevel(impl.Object);
  47. Assert.Equal(double.NaN, target.Width);
  48. }
  49. }
  50. [Fact]
  51. public void Height_Should_Not_Be_Set_On_Construction()
  52. {
  53. using (UnitTestApplication.Start(TestServices.StyledWindow))
  54. {
  55. var impl = new Mock<ITopLevelImpl>();
  56. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  57. var target = new TestTopLevel(impl.Object);
  58. Assert.Equal(double.NaN, target.Height);
  59. }
  60. }
  61. [Fact]
  62. public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
  63. {
  64. var services = TestServices.StyledWindow;
  65. using (UnitTestApplication.Start(services))
  66. {
  67. var impl = new Mock<ITopLevelImpl>();
  68. var target = new TestTopLevel(impl.Object, Mock.Of<ILayoutManager>());
  69. // The layout pass should be scheduled by the derived class.
  70. var layoutManagerMock = Mock.Get(target.LayoutManager);
  71. layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
  72. }
  73. }
  74. [Fact]
  75. public void Bounds_Should_Be_Set_After_Layout_Pass()
  76. {
  77. using (UnitTestApplication.Start(TestServices.StyledWindow))
  78. {
  79. var impl = new Mock<ITopLevelImpl>();
  80. impl.SetupProperty(x => x.Resized);
  81. impl.SetupGet(x => x.Scaling).Returns(1);
  82. var target = new TestTopLevel(impl.Object)
  83. {
  84. IsVisible = true,
  85. Template = CreateTemplate(),
  86. Content = new TextBlock
  87. {
  88. Width = 321,
  89. Height = 432,
  90. }
  91. };
  92. target.LayoutManager.ExecuteInitialLayoutPass(target);
  93. Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
  94. }
  95. }
  96. [Fact]
  97. public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
  98. {
  99. using (UnitTestApplication.Start(TestServices.StyledWindow))
  100. {
  101. var impl = new Mock<ITopLevelImpl>();
  102. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  103. var target = new TestTopLevel(impl.Object);
  104. target.LayoutManager.ExecuteLayoutPass();
  105. Assert.Equal(double.NaN, target.Width);
  106. Assert.Equal(double.NaN, target.Height);
  107. }
  108. }
  109. [Fact]
  110. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  111. {
  112. using (UnitTestApplication.Start(TestServices.StyledWindow))
  113. {
  114. var impl = new Mock<ITopLevelImpl>();
  115. impl.SetupAllProperties();
  116. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  117. // The user has resized the window, so we can no longer auto-size.
  118. var target = new TestTopLevel(impl.Object);
  119. impl.Object.Resized(new Size(100, 200));
  120. Assert.Equal(100, target.Width);
  121. Assert.Equal(200, target.Height);
  122. }
  123. }
  124. [Fact]
  125. public void Impl_Close_Should_Call_Raise_Closed_Event()
  126. {
  127. using (UnitTestApplication.Start(TestServices.StyledWindow))
  128. {
  129. var impl = new Mock<ITopLevelImpl>();
  130. impl.SetupAllProperties();
  131. bool raised = false;
  132. var target = new TestTopLevel(impl.Object);
  133. target.Closed += (s, e) => raised = true;
  134. impl.Object.Closed();
  135. Assert.True(raised);
  136. }
  137. }
  138. [Fact]
  139. public void Impl_Close_Should_Raise_DetachedFromLogicalTree_Event()
  140. {
  141. using (UnitTestApplication.Start(TestServices.StyledWindow))
  142. {
  143. var impl = new Mock<ITopLevelImpl>();
  144. impl.SetupAllProperties();
  145. var target = new TestTopLevel(impl.Object);
  146. var raised = 0;
  147. target.DetachedFromLogicalTree += (s, e) =>
  148. {
  149. Assert.Same(target, e.Root);
  150. Assert.Same(target, e.Source);
  151. Assert.Null(e.Parent);
  152. ++raised;
  153. };
  154. impl.Object.Closed();
  155. Assert.Equal(1, raised);
  156. }
  157. }
  158. [Fact]
  159. public void Impl_Input_Should_Pass_Input_To_InputManager()
  160. {
  161. var inputManagerMock = new Mock<IInputManager>();
  162. var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
  163. using (UnitTestApplication.Start(services))
  164. {
  165. var impl = new Mock<ITopLevelImpl>();
  166. impl.SetupAllProperties();
  167. var target = new TestTopLevel(impl.Object);
  168. var input = new RawKeyEventArgs(
  169. new Mock<IKeyboardDevice>().Object,
  170. 0,
  171. target,
  172. RawKeyEventType.KeyDown,
  173. Key.A, RawInputModifiers.None);
  174. impl.Object.Input(input);
  175. inputManagerMock.Verify(x => x.ProcessInput(input));
  176. }
  177. }
  178. [Fact]
  179. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  180. {
  181. using (UnitTestApplication.Start(TestServices.StyledWindow))
  182. {
  183. var impl = new Mock<ITopLevelImpl>();
  184. impl.SetupAllProperties();
  185. var target = new TestTopLevel(impl.Object);
  186. var child = new TestTopLevel(impl.Object);
  187. target.Template = CreateTemplate();
  188. target.Content = child;
  189. target.ApplyTemplate();
  190. Assert.Throws<InvalidOperationException>(() => target.Presenter.ApplyTemplate());
  191. }
  192. }
  193. [Fact]
  194. public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
  195. {
  196. using (UnitTestApplication.Start(TestServices.StyledWindow))
  197. {
  198. var impl = new Mock<ITopLevelImpl>();
  199. impl.SetupAllProperties();
  200. var target = new TestTopLevel(impl.Object);
  201. var raised = false;
  202. target.ResourcesChanged += (_, __) => raised = true;
  203. Application.Current.Resources.Add("foo", "bar");
  204. Assert.True(raised);
  205. }
  206. }
  207. [Fact]
  208. public void Close_Should_Notify_MouseDevice()
  209. {
  210. using (UnitTestApplication.Start(TestServices.StyledWindow))
  211. {
  212. var impl = new Mock<ITopLevelImpl>();
  213. var mouseDevice = new Mock<IMouseDevice>();
  214. impl.SetupAllProperties();
  215. impl.Setup(x => x.MouseDevice).Returns(mouseDevice.Object);
  216. var target = new TestTopLevel(impl.Object);
  217. impl.Object.Closed();
  218. mouseDevice.Verify(x => x.TopLevelClosed(target));
  219. }
  220. }
  221. private FuncControlTemplate<TestTopLevel> CreateTemplate()
  222. {
  223. return new FuncControlTemplate<TestTopLevel>((x, scope) =>
  224. new ContentPresenter
  225. {
  226. Name = "PART_ContentPresenter",
  227. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  228. }.RegisterInNameScope(scope));
  229. }
  230. private class TestTopLevel : TopLevel
  231. {
  232. private readonly ILayoutManager _layoutManager;
  233. public bool IsClosed { get; private set; }
  234. public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
  235. : base(impl)
  236. {
  237. _layoutManager = layoutManager ?? new LayoutManager();
  238. }
  239. protected override ILayoutManager CreateLayoutManager() => _layoutManager;
  240. }
  241. }
  242. }