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