TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using System;
  2. using Avalonia.Controls.Presenters;
  3. using Avalonia.Controls.Templates;
  4. using Avalonia.Input;
  5. using Avalonia.Input.Platform;
  6. using Avalonia.Input.Raw;
  7. using Avalonia.Layout;
  8. using Avalonia.LogicalTree;
  9. using Avalonia.Platform;
  10. using Avalonia.Rendering;
  11. using Avalonia.Rendering.Composition;
  12. using Avalonia.Styling;
  13. using Avalonia.UnitTests;
  14. using Moq;
  15. using Xunit;
  16. using static Avalonia.Controls.UnitTests.MaskedTextBoxTests;
  17. namespace Avalonia.Controls.UnitTests
  18. {
  19. public class TopLevelTests : ScopedTestBase
  20. {
  21. [Fact]
  22. public void IsAttachedToLogicalTree_Is_True()
  23. {
  24. using (UnitTestApplication.Start(TestServices.StyledWindow))
  25. {
  26. var impl = CreateMockTopLevelImpl();
  27. var target = new TestTopLevel(impl.Object);
  28. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  29. }
  30. }
  31. [Fact]
  32. public void ClientSize_Should_Be_Set_On_Construction()
  33. {
  34. using (UnitTestApplication.Start(TestServices.StyledWindow))
  35. {
  36. var impl = CreateMockTopLevelImpl();
  37. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  38. var target = new TestTopLevel(impl.Object);
  39. Assert.Equal(new Size(123, 456), target.ClientSize);
  40. }
  41. }
  42. [Fact]
  43. public void Width_Should_Not_Be_Set_On_Construction()
  44. {
  45. using (UnitTestApplication.Start(TestServices.StyledWindow))
  46. {
  47. var impl = CreateMockTopLevelImpl();
  48. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  49. var target = new TestTopLevel(impl.Object);
  50. Assert.Equal(double.NaN, target.Width);
  51. }
  52. }
  53. [Fact]
  54. public void Height_Should_Not_Be_Set_On_Construction()
  55. {
  56. using (UnitTestApplication.Start(TestServices.StyledWindow))
  57. {
  58. var impl = CreateMockTopLevelImpl();
  59. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  60. var target = new TestTopLevel(impl.Object);
  61. Assert.Equal(double.NaN, target.Height);
  62. }
  63. }
  64. [Fact]
  65. public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
  66. {
  67. var services = TestServices.StyledWindow;
  68. using (UnitTestApplication.Start(services))
  69. {
  70. var impl = CreateMockTopLevelImpl();
  71. var target = new TestTopLevel(impl.Object, Mock.Of<ILayoutManager>());
  72. // The layout pass should be scheduled by the derived class.
  73. var layoutManagerMock = Mock.Get(target.LayoutManager);
  74. layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
  75. }
  76. }
  77. [Fact]
  78. public void Bounds_Should_Be_Set_After_Layout_Pass()
  79. {
  80. using (UnitTestApplication.Start(TestServices.StyledWindow))
  81. {
  82. var impl = CreateMockTopLevelImpl();
  83. impl.SetupProperty(x => x.Resized);
  84. impl.SetupGet(x => x.RenderScaling).Returns(1);
  85. var target = new TestTopLevel(impl.Object)
  86. {
  87. IsVisible = true,
  88. Template = CreateTemplate(),
  89. Content = new TextBlock
  90. {
  91. Width = 321,
  92. Height = 432,
  93. }
  94. };
  95. target.LayoutManager.ExecuteInitialLayoutPass();
  96. Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
  97. }
  98. }
  99. [Fact]
  100. public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
  101. {
  102. using (UnitTestApplication.Start(TestServices.StyledWindow))
  103. {
  104. var impl = CreateMockTopLevelImpl();
  105. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  106. var target = new TestTopLevel(impl.Object);
  107. target.LayoutManager.ExecuteLayoutPass();
  108. Assert.Equal(double.NaN, target.Width);
  109. Assert.Equal(double.NaN, target.Height);
  110. }
  111. }
  112. [Fact]
  113. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  114. {
  115. using (UnitTestApplication.Start(TestServices.StyledWindow))
  116. {
  117. var impl = CreateMockTopLevelImpl(true);
  118. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  119. // The user has resized the window, so we can no longer auto-size.
  120. var target = new TestTopLevel(impl.Object);
  121. impl.Object.Resized(new Size(100, 200), WindowResizeReason.Unspecified);
  122. Assert.Equal(100, target.Width);
  123. Assert.Equal(200, target.Height);
  124. }
  125. }
  126. [Fact]
  127. public void Impl_Close_Should_Call_Raise_Closed_Event()
  128. {
  129. using (UnitTestApplication.Start(TestServices.StyledWindow))
  130. {
  131. var impl = CreateMockTopLevelImpl(true);
  132. bool raised = false;
  133. var target = new TestTopLevel(impl.Object);
  134. target.Closed += (s, e) => raised = true;
  135. impl.Object.Closed();
  136. Assert.True(raised);
  137. }
  138. }
  139. [Fact]
  140. public void Impl_Close_Should_Raise_DetachedFromLogicalTree_Event()
  141. {
  142. using (UnitTestApplication.Start(TestServices.StyledWindow))
  143. {
  144. var impl = CreateMockTopLevelImpl(true);
  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. inputManagerMock.DefaultValue = DefaultValue.Mock;
  163. inputManagerMock.SetupAllProperties();
  164. var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
  165. using (UnitTestApplication.Start(services))
  166. {
  167. var impl = CreateMockTopLevelImpl(true);
  168. var target = new TestTopLevel(impl.Object);
  169. var input = new RawKeyEventArgs(
  170. new Mock<IKeyboardDevice>().Object,
  171. 0,
  172. target,
  173. RawKeyEventType.KeyDown,
  174. Key.A,
  175. RawInputModifiers.None,
  176. PhysicalKey.A,
  177. "a");
  178. impl.Object.Input(input);
  179. inputManagerMock.Verify(x => x.ProcessInput(input));
  180. }
  181. }
  182. [Fact]
  183. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  184. {
  185. using (UnitTestApplication.Start(TestServices.StyledWindow))
  186. {
  187. var impl = CreateMockTopLevelImpl(true);
  188. var target = new TestTopLevel(impl.Object);
  189. var child = new TestTopLevel(impl.Object);
  190. target.Template = CreateTemplate();
  191. target.Content = child;
  192. target.ApplyTemplate();
  193. Assert.Throws<InvalidOperationException>(() => target.Presenter.ApplyTemplate());
  194. }
  195. }
  196. [Fact]
  197. public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
  198. {
  199. using (UnitTestApplication.Start(TestServices.StyledWindow))
  200. {
  201. var impl = CreateMockTopLevelImpl(true);
  202. var target = new TestTopLevel(impl.Object);
  203. var raised = false;
  204. target.ResourcesChanged += (_, __) => raised = true;
  205. Application.Current.Resources.Add("foo", "bar");
  206. Assert.True(raised);
  207. }
  208. }
  209. [Fact]
  210. public void Close_Should_Dispose_LayoutManager()
  211. {
  212. using (UnitTestApplication.Start(TestServices.StyledWindow))
  213. {
  214. var impl = CreateMockTopLevelImpl(true);
  215. var layoutManager = new Mock<ILayoutManager>();
  216. var target = new TestTopLevel(impl.Object, layoutManager.Object);
  217. impl.Object.Closed();
  218. layoutManager.Verify(x => x.Dispose());
  219. }
  220. }
  221. [Fact]
  222. public void Reacts_To_Changes_In_Global_Styles()
  223. {
  224. using (UnitTestApplication.Start(TestServices.StyledWindow))
  225. {
  226. var impl = CreateMockTopLevelImpl();
  227. impl.SetupGet(x => x.RenderScaling).Returns(1);
  228. var child = new Border { Classes = { "foo" } };
  229. var target = new TestTopLevel(impl.Object)
  230. {
  231. Template = CreateTemplate(),
  232. Content = child,
  233. };
  234. target.LayoutManager.ExecuteInitialLayoutPass();
  235. Assert.Equal(new Thickness(0), child.BorderThickness);
  236. var style = new Style(x => x.OfType<Border>().Class("foo"))
  237. {
  238. Setters =
  239. {
  240. new Setter(Border.BorderThicknessProperty, new Thickness(2))
  241. }
  242. };
  243. Application.Current.Styles.Add(style);
  244. target.LayoutManager.ExecuteInitialLayoutPass();
  245. Assert.Equal(new Thickness(2), child.BorderThickness);
  246. Application.Current.Styles.Remove(style);
  247. Assert.Equal(new Thickness(0), child.BorderThickness);
  248. }
  249. }
  250. private static FuncControlTemplate<TestTopLevel> CreateTemplate()
  251. {
  252. return new FuncControlTemplate<TestTopLevel>((x, scope) =>
  253. new ContentPresenter
  254. {
  255. Name = "PART_ContentPresenter",
  256. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  257. }.RegisterInNameScope(scope));
  258. }
  259. private static Mock<ITopLevelImpl> CreateMockTopLevelImpl(bool setupProperties = false)
  260. {
  261. var topLevel = new Mock<ITopLevelImpl>();
  262. if (setupProperties)
  263. topLevel.SetupAllProperties();
  264. topLevel.Setup(x => x.RenderScaling).Returns(1);
  265. topLevel.Setup(x => x.Compositor).Returns(RendererMocks.CreateDummyCompositor());
  266. return topLevel;
  267. }
  268. private class TestTopLevel : TopLevel
  269. {
  270. private readonly ILayoutManager _layoutManager;
  271. public bool IsClosed { get; private set; }
  272. public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
  273. : base(impl)
  274. {
  275. _layoutManager = layoutManager ?? new LayoutManager(this);
  276. }
  277. private protected override ILayoutManager CreateLayoutManager() => _layoutManager;
  278. }
  279. }
  280. }