TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Copyright (c) The Perspex 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 System.Reactive;
  5. using System.Reactive.Subjects;
  6. using Moq;
  7. using Perspex.Controls.Presenters;
  8. using Perspex.Controls.Templates;
  9. using Perspex.Input;
  10. using Perspex.Input.Raw;
  11. using Perspex.Layout;
  12. using Perspex.Platform;
  13. using Perspex.Rendering;
  14. using Perspex.Styling;
  15. using Ploeh.AutoFixture;
  16. using Ploeh.AutoFixture.AutoMoq;
  17. using Xunit;
  18. namespace Perspex.Controls.UnitTests
  19. {
  20. public class TopLevelTests
  21. {
  22. [Fact]
  23. public void ClientSize_Should_Be_Set_On_Construction()
  24. {
  25. using (PerspexLocator.EnterScope())
  26. {
  27. RegisterServices();
  28. var impl = new Mock<ITopLevelImpl>();
  29. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  30. var target = new TestTopLevel(impl.Object);
  31. Assert.Equal(new Size(123, 456), target.ClientSize);
  32. }
  33. }
  34. [Fact]
  35. public void Width_Should_Not_Be_Set_On_Construction()
  36. {
  37. using (PerspexLocator.EnterScope())
  38. {
  39. RegisterServices();
  40. var impl = new Mock<ITopLevelImpl>();
  41. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  42. var target = new TestTopLevel(impl.Object);
  43. Assert.Equal(double.NaN, target.Width);
  44. }
  45. }
  46. [Fact]
  47. public void Height_Should_Not_Be_Set_On_Construction()
  48. {
  49. using (PerspexLocator.EnterScope())
  50. {
  51. RegisterServices();
  52. var impl = new Mock<ITopLevelImpl>();
  53. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  54. var target = new TestTopLevel(impl.Object);
  55. Assert.Equal(double.NaN, target.Height);
  56. }
  57. }
  58. [Fact]
  59. public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
  60. {
  61. using (PerspexLocator.EnterScope())
  62. {
  63. RegisterServices();
  64. var impl = new Mock<ITopLevelImpl>();
  65. var target = new TestTopLevel(impl.Object);
  66. // The layout pass should be scheduled by the derived class.
  67. var layoutManagerMock = Mock.Get(LayoutManager.Instance);
  68. layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
  69. }
  70. }
  71. [Fact]
  72. public void Bounds_Should_Be_Set_After_Layout_Pass()
  73. {
  74. using (PerspexLocator.EnterScope())
  75. {
  76. RegisterServices();
  77. PerspexLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(new LayoutManager());
  78. var impl = new Mock<ITopLevelImpl>();
  79. impl.SetupProperty(x => x.ClientSize);
  80. impl.SetupProperty(x => x.Resized);
  81. impl.SetupGet(x => x.Scaling).Returns(1);
  82. var target = new TestTopLevel(impl.Object)
  83. {
  84. Template = CreateTemplate(),
  85. Content = new TextBlock
  86. {
  87. Width = 321,
  88. Height = 432,
  89. }
  90. };
  91. LayoutManager.Instance.ExecuteInitialLayoutPass(target);
  92. Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
  93. }
  94. }
  95. [Fact]
  96. public void Impl_ClientSize_Should_Be_Set_After_Layout_Pass()
  97. {
  98. using (PerspexLocator.EnterScope())
  99. {
  100. RegisterServices();
  101. PerspexLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(new LayoutManager());
  102. var impl = Mock.Of<ITopLevelImpl>(x => x.Scaling == 1);
  103. var target = new TestTopLevel(impl)
  104. {
  105. Template = CreateTemplate(),
  106. Content = new TextBlock
  107. {
  108. Width = 321,
  109. Height = 432,
  110. }
  111. };
  112. LayoutManager.Instance.ExecuteInitialLayoutPass(target);
  113. Mock.Get(impl).VerifySet(x => x.ClientSize = new Size(321, 432));
  114. }
  115. }
  116. [Fact]
  117. public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
  118. {
  119. using (PerspexLocator.EnterScope())
  120. {
  121. RegisterServices();
  122. var impl = new Mock<ITopLevelImpl>();
  123. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  124. var target = new TestTopLevel(impl.Object);
  125. LayoutManager.Instance.ExecuteLayoutPass();
  126. Assert.Equal(double.NaN, target.Width);
  127. Assert.Equal(double.NaN, target.Height);
  128. }
  129. }
  130. [Fact]
  131. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  132. {
  133. using (PerspexLocator.EnterScope())
  134. {
  135. RegisterServices();
  136. var impl = new Mock<ITopLevelImpl>();
  137. impl.SetupAllProperties();
  138. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  139. // The user has resized the window, so we can no longer auto-size.
  140. var target = new TestTopLevel(impl.Object);
  141. impl.Object.Resized(new Size(100, 200));
  142. Assert.Equal(100, target.Width);
  143. Assert.Equal(200, target.Height);
  144. }
  145. }
  146. [Fact]
  147. public void Activate_Should_Call_Impl_Activate()
  148. {
  149. using (PerspexLocator.EnterScope())
  150. {
  151. RegisterServices();
  152. var impl = new Mock<ITopLevelImpl>();
  153. var target = new TestTopLevel(impl.Object);
  154. target.Activate();
  155. impl.Verify(x => x.Activate());
  156. }
  157. }
  158. [Fact]
  159. public void Impl_Activate_Should_Call_Raise_Activated_Event()
  160. {
  161. using (PerspexLocator.EnterScope())
  162. {
  163. RegisterServices();
  164. var impl = new Mock<ITopLevelImpl>();
  165. impl.SetupAllProperties();
  166. bool raised = false;
  167. var target = new TestTopLevel(impl.Object);
  168. target.Activated += (s, e) => raised = true;
  169. impl.Object.Activated();
  170. Assert.True(raised);
  171. }
  172. }
  173. [Fact]
  174. public void Impl_Close_Should_Call_Raise_Closed_Event()
  175. {
  176. using (PerspexLocator.EnterScope())
  177. {
  178. RegisterServices();
  179. var impl = new Mock<ITopLevelImpl>();
  180. impl.SetupAllProperties();
  181. bool raised = false;
  182. var target = new TestTopLevel(impl.Object);
  183. target.Closed += (s, e) => raised = true;
  184. impl.Object.Closed();
  185. Assert.True(raised);
  186. }
  187. }
  188. [Fact]
  189. public void Impl_Deactivate_Should_Call_Raise_Activated_Event()
  190. {
  191. using (PerspexLocator.EnterScope())
  192. {
  193. RegisterServices();
  194. var impl = new Mock<ITopLevelImpl>();
  195. impl.SetupAllProperties();
  196. bool raised = false;
  197. var target = new TestTopLevel(impl.Object);
  198. target.Deactivated += (s, e) => raised = true;
  199. impl.Object.Deactivated();
  200. Assert.True(raised);
  201. }
  202. }
  203. [Fact]
  204. public void Impl_Input_Should_Pass_Input_To_InputManager()
  205. {
  206. using (PerspexLocator.EnterScope())
  207. {
  208. RegisterServices();
  209. var impl = new Mock<ITopLevelImpl>();
  210. impl.SetupAllProperties();
  211. var target = new TestTopLevel(impl.Object);
  212. var input = new RawKeyEventArgs(
  213. new Mock<IKeyboardDevice>().Object,
  214. 0,
  215. RawKeyEventType.KeyDown,
  216. Key.A, InputModifiers.None);
  217. impl.Object.Input(input);
  218. var inputManagerMock = Mock.Get(InputManager.Instance);
  219. inputManagerMock.Verify(x => x.Process(input));
  220. }
  221. }
  222. [Fact]
  223. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  224. {
  225. using (PerspexLocator.EnterScope())
  226. {
  227. RegisterServices();
  228. var impl = new Mock<ITopLevelImpl>();
  229. impl.SetupAllProperties();
  230. var target = new TestTopLevel(impl.Object);
  231. var child = new TestTopLevel(impl.Object);
  232. target.Template = CreateTemplate();
  233. target.Content = child;
  234. Assert.Throws<InvalidOperationException>(() => target.ApplyTemplate());
  235. }
  236. }
  237. private FuncControlTemplate<TestTopLevel> CreateTemplate()
  238. {
  239. return new FuncControlTemplate<TestTopLevel>(x =>
  240. new ContentPresenter
  241. {
  242. Name = "PART_ContentPresenter",
  243. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  244. });
  245. }
  246. private void RegisterServices()
  247. {
  248. var fixture = new Fixture().Customize(new AutoMoqCustomization());
  249. var l = PerspexLocator.CurrentMutable;
  250. var formattedText = fixture.Create<IFormattedTextImpl>();
  251. var globalStyles = new Mock<IGlobalStyles>();
  252. var layoutManager = fixture.Create<ILayoutManager>();
  253. var renderInterface = fixture.Create<IPlatformRenderInterface>();
  254. var renderManager = fixture.Create<IRenderQueueManager>();
  255. var windowImpl = new Mock<IWindowImpl>();
  256. var theme = new Styles();
  257. globalStyles.Setup(x => x.Styles).Returns(theme);
  258. PerspexLocator.CurrentMutable
  259. .Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
  260. .Bind<IFocusManager>().ToConstant(new Mock<IFocusManager>().Object)
  261. .Bind<IGlobalStyles>().ToConstant(globalStyles.Object)
  262. .Bind<ILayoutManager>().ToConstant(layoutManager)
  263. .Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
  264. .Bind<IRenderQueueManager>().ToConstant(renderManager)
  265. .Bind<IStyler>().ToConstant(new Styler());
  266. }
  267. private class TestTopLevel : TopLevel
  268. {
  269. public TestTopLevel(ITopLevelImpl impl)
  270. : base(impl)
  271. {
  272. }
  273. }
  274. }
  275. }