TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. using System;
  2. using Avalonia.Controls.Presenters;
  3. using Avalonia.Controls.Templates;
  4. using Avalonia.Input;
  5. using Avalonia.Input.Raw;
  6. using Avalonia.Layout;
  7. using Avalonia.LogicalTree;
  8. using Avalonia.Platform;
  9. using Avalonia.Styling;
  10. using Avalonia.UnitTests;
  11. using Moq;
  12. using Xunit;
  13. namespace Avalonia.Controls.UnitTests
  14. {
  15. public class TopLevelTests
  16. {
  17. [Fact]
  18. public void IsAttachedToLogicalTree_Is_True()
  19. {
  20. using (UnitTestApplication.Start(TestServices.StyledWindow))
  21. {
  22. var impl = new Mock<ITopLevelImpl>();
  23. var target = new TestTopLevel(impl.Object);
  24. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  25. }
  26. }
  27. [Fact]
  28. public void ClientSize_Should_Be_Set_On_Construction()
  29. {
  30. using (UnitTestApplication.Start(TestServices.StyledWindow))
  31. {
  32. var impl = new Mock<ITopLevelImpl>();
  33. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  34. var target = new TestTopLevel(impl.Object);
  35. Assert.Equal(new Size(123, 456), target.ClientSize);
  36. }
  37. }
  38. [Fact]
  39. public void Width_Should_Not_Be_Set_On_Construction()
  40. {
  41. using (UnitTestApplication.Start(TestServices.StyledWindow))
  42. {
  43. var impl = new Mock<ITopLevelImpl>();
  44. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  45. var target = new TestTopLevel(impl.Object);
  46. Assert.Equal(double.NaN, target.Width);
  47. }
  48. }
  49. [Fact]
  50. public void Height_Should_Not_Be_Set_On_Construction()
  51. {
  52. using (UnitTestApplication.Start(TestServices.StyledWindow))
  53. {
  54. var impl = new Mock<ITopLevelImpl>();
  55. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  56. var target = new TestTopLevel(impl.Object);
  57. Assert.Equal(double.NaN, target.Height);
  58. }
  59. }
  60. [Fact]
  61. public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
  62. {
  63. var services = TestServices.StyledWindow;
  64. using (UnitTestApplication.Start(services))
  65. {
  66. var impl = new Mock<ITopLevelImpl>();
  67. var target = new TestTopLevel(impl.Object, Mock.Of<ILayoutManager>());
  68. // The layout pass should be scheduled by the derived class.
  69. var layoutManagerMock = Mock.Get(target.LayoutManager);
  70. layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
  71. }
  72. }
  73. [Fact]
  74. public void Bounds_Should_Be_Set_After_Layout_Pass()
  75. {
  76. using (UnitTestApplication.Start(TestServices.StyledWindow))
  77. {
  78. var impl = new Mock<ITopLevelImpl>();
  79. impl.SetupProperty(x => x.Resized);
  80. impl.SetupGet(x => x.RenderScaling).Returns(1);
  81. var target = new TestTopLevel(impl.Object)
  82. {
  83. IsVisible = true,
  84. Template = CreateTemplate(),
  85. Content = new TextBlock
  86. {
  87. Width = 321,
  88. Height = 432,
  89. }
  90. };
  91. target.LayoutManager.ExecuteInitialLayoutPass();
  92. Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
  93. }
  94. }
  95. [Fact]
  96. public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
  97. {
  98. using (UnitTestApplication.Start(TestServices.StyledWindow))
  99. {
  100. var impl = new Mock<ITopLevelImpl>();
  101. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  102. var target = new TestTopLevel(impl.Object);
  103. target.LayoutManager.ExecuteLayoutPass();
  104. Assert.Equal(double.NaN, target.Width);
  105. Assert.Equal(double.NaN, target.Height);
  106. }
  107. }
  108. [Fact]
  109. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  110. {
  111. using (UnitTestApplication.Start(TestServices.StyledWindow))
  112. {
  113. var impl = new Mock<ITopLevelImpl>();
  114. impl.SetupAllProperties();
  115. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  116. // The user has resized the window, so we can no longer auto-size.
  117. var target = new TestTopLevel(impl.Object);
  118. impl.Object.Resized(new Size(100, 200), PlatformResizeReason.Unspecified);
  119. Assert.Equal(100, target.Width);
  120. Assert.Equal(200, target.Height);
  121. }
  122. }
  123. [Fact]
  124. public void Impl_Close_Should_Call_Raise_Closed_Event()
  125. {
  126. using (UnitTestApplication.Start(TestServices.StyledWindow))
  127. {
  128. var impl = new Mock<ITopLevelImpl>();
  129. impl.SetupAllProperties();
  130. bool raised = false;
  131. var target = new TestTopLevel(impl.Object);
  132. target.Closed += (s, e) => raised = true;
  133. impl.Object.Closed();
  134. Assert.True(raised);
  135. }
  136. }
  137. [Fact]
  138. public void Impl_Close_Should_Raise_DetachedFromLogicalTree_Event()
  139. {
  140. using (UnitTestApplication.Start(TestServices.StyledWindow))
  141. {
  142. var impl = new Mock<ITopLevelImpl>();
  143. impl.SetupAllProperties();
  144. var target = new TestTopLevel(impl.Object);
  145. var raised = 0;
  146. target.DetachedFromLogicalTree += (s, e) =>
  147. {
  148. Assert.Same(target, e.Root);
  149. Assert.Same(target, e.Source);
  150. Assert.Null(e.Parent);
  151. ++raised;
  152. };
  153. impl.Object.Closed();
  154. Assert.Equal(1, raised);
  155. }
  156. }
  157. [Fact]
  158. public void Impl_Input_Should_Pass_Input_To_InputManager()
  159. {
  160. var inputManagerMock = new Mock<IInputManager>();
  161. inputManagerMock.DefaultValue = DefaultValue.Mock;
  162. inputManagerMock.SetupAllProperties();
  163. var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
  164. using (UnitTestApplication.Start(services))
  165. {
  166. var impl = new Mock<ITopLevelImpl>();
  167. impl.SetupAllProperties();
  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, RawInputModifiers.None);
  175. impl.Object.Input(input);
  176. inputManagerMock.Verify(x => x.ProcessInput(input));
  177. }
  178. }
  179. [Fact]
  180. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  181. {
  182. using (UnitTestApplication.Start(TestServices.StyledWindow))
  183. {
  184. var impl = new Mock<ITopLevelImpl>();
  185. impl.SetupAllProperties();
  186. var target = new TestTopLevel(impl.Object);
  187. var child = new TestTopLevel(impl.Object);
  188. target.Template = CreateTemplate();
  189. target.Content = child;
  190. target.ApplyTemplate();
  191. Assert.Throws<InvalidOperationException>(() => target.Presenter.ApplyTemplate());
  192. }
  193. }
  194. [Fact]
  195. public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
  196. {
  197. using (UnitTestApplication.Start(TestServices.StyledWindow))
  198. {
  199. var impl = new Mock<ITopLevelImpl>();
  200. impl.SetupAllProperties();
  201. var target = new TestTopLevel(impl.Object);
  202. var raised = false;
  203. target.ResourcesChanged += (_, __) => raised = true;
  204. Application.Current.Resources.Add("foo", "bar");
  205. Assert.True(raised);
  206. }
  207. }
  208. [Fact]
  209. public void Close_Should_Dispose_LayoutManager()
  210. {
  211. using (UnitTestApplication.Start(TestServices.StyledWindow))
  212. {
  213. var impl = new Mock<ITopLevelImpl>();
  214. impl.SetupAllProperties();
  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 = new Mock<ITopLevelImpl>();
  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 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 class TestTopLevel : TopLevel
  260. {
  261. private readonly ILayoutManager _layoutManager;
  262. public bool IsClosed { get; private set; }
  263. public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
  264. : base(impl)
  265. {
  266. _layoutManager = layoutManager ?? new LayoutManager(this);
  267. }
  268. protected override ILayoutManager CreateLayoutManager() => _layoutManager;
  269. }
  270. }
  271. }