TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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));
  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. var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
  162. using (UnitTestApplication.Start(services))
  163. {
  164. var impl = new Mock<ITopLevelImpl>();
  165. impl.SetupAllProperties();
  166. var target = new TestTopLevel(impl.Object);
  167. var input = new RawKeyEventArgs(
  168. new Mock<IKeyboardDevice>().Object,
  169. 0,
  170. target,
  171. RawKeyEventType.KeyDown,
  172. Key.A, RawInputModifiers.None);
  173. impl.Object.Input(input);
  174. inputManagerMock.Verify(x => x.ProcessInput(input));
  175. }
  176. }
  177. [Fact]
  178. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  179. {
  180. using (UnitTestApplication.Start(TestServices.StyledWindow))
  181. {
  182. var impl = new Mock<ITopLevelImpl>();
  183. impl.SetupAllProperties();
  184. var target = new TestTopLevel(impl.Object);
  185. var child = new TestTopLevel(impl.Object);
  186. target.Template = CreateTemplate();
  187. target.Content = child;
  188. target.ApplyTemplate();
  189. Assert.Throws<InvalidOperationException>(() => target.Presenter.ApplyTemplate());
  190. }
  191. }
  192. [Fact]
  193. public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
  194. {
  195. using (UnitTestApplication.Start(TestServices.StyledWindow))
  196. {
  197. var impl = new Mock<ITopLevelImpl>();
  198. impl.SetupAllProperties();
  199. var target = new TestTopLevel(impl.Object);
  200. var raised = false;
  201. target.ResourcesChanged += (_, __) => raised = true;
  202. Application.Current.Resources.Add("foo", "bar");
  203. Assert.True(raised);
  204. }
  205. }
  206. [Fact]
  207. public void Close_Should_Notify_MouseDevice()
  208. {
  209. using (UnitTestApplication.Start(TestServices.StyledWindow))
  210. {
  211. var impl = new Mock<ITopLevelImpl>();
  212. var mouseDevice = new Mock<IMouseDevice>();
  213. impl.SetupAllProperties();
  214. impl.Setup(x => x.MouseDevice).Returns(mouseDevice.Object);
  215. var target = new TestTopLevel(impl.Object);
  216. impl.Object.Closed();
  217. mouseDevice.Verify(x => x.TopLevelClosed(target));
  218. }
  219. }
  220. [Fact]
  221. public void Close_Should_Dispose_LayoutManager()
  222. {
  223. using (UnitTestApplication.Start(TestServices.StyledWindow))
  224. {
  225. var impl = new Mock<ITopLevelImpl>();
  226. impl.SetupAllProperties();
  227. var layoutManager = new Mock<ILayoutManager>();
  228. var target = new TestTopLevel(impl.Object, layoutManager.Object);
  229. impl.Object.Closed();
  230. layoutManager.Verify(x => x.Dispose());
  231. }
  232. }
  233. [Fact]
  234. public void Reacts_To_Changes_In_Global_Styles()
  235. {
  236. using (UnitTestApplication.Start(TestServices.StyledWindow))
  237. {
  238. var impl = new Mock<ITopLevelImpl>();
  239. impl.SetupGet(x => x.RenderScaling).Returns(1);
  240. var child = new Border { Classes = { "foo" } };
  241. var target = new TestTopLevel(impl.Object)
  242. {
  243. Template = CreateTemplate(),
  244. Content = child,
  245. };
  246. target.LayoutManager.ExecuteInitialLayoutPass();
  247. Assert.Equal(new Thickness(0), child.BorderThickness);
  248. var style = new Style(x => x.OfType<Border>().Class("foo"))
  249. {
  250. Setters =
  251. {
  252. new Setter(Border.BorderThicknessProperty, new Thickness(2))
  253. }
  254. };
  255. Application.Current.Styles.Add(style);
  256. target.LayoutManager.ExecuteInitialLayoutPass();
  257. Assert.Equal(new Thickness(2), child.BorderThickness);
  258. Application.Current.Styles.Remove(style);
  259. Assert.Equal(new Thickness(0), child.BorderThickness);
  260. }
  261. }
  262. private FuncControlTemplate<TestTopLevel> CreateTemplate()
  263. {
  264. return new FuncControlTemplate<TestTopLevel>((x, scope) =>
  265. new ContentPresenter
  266. {
  267. Name = "PART_ContentPresenter",
  268. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  269. }.RegisterInNameScope(scope));
  270. }
  271. private class TestTopLevel : TopLevel
  272. {
  273. private readonly ILayoutManager _layoutManager;
  274. public bool IsClosed { get; private set; }
  275. public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
  276. : base(impl)
  277. {
  278. _layoutManager = layoutManager ?? new LayoutManager(this);
  279. }
  280. protected override ILayoutManager CreateLayoutManager() => _layoutManager;
  281. }
  282. }
  283. }