TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. var target = new TestTopLevel(impl.Object)
  82. {
  83. Template = CreateTemplate(),
  84. Content = new TextBlock
  85. {
  86. Width = 321,
  87. Height = 432,
  88. }
  89. };
  90. LayoutManager.Instance.ExecuteInitialLayoutPass(target);
  91. Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
  92. }
  93. }
  94. [Fact]
  95. public void Impl_ClientSize_Should_Be_Set_After_Layout_Pass()
  96. {
  97. using (PerspexLocator.EnterScope())
  98. {
  99. RegisterServices();
  100. PerspexLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(new LayoutManager());
  101. var impl = new Mock<ITopLevelImpl>();
  102. var target = new TestTopLevel(impl.Object)
  103. {
  104. Template = CreateTemplate(),
  105. Content = new TextBlock
  106. {
  107. Width = 321,
  108. Height = 432,
  109. }
  110. };
  111. LayoutManager.Instance.ExecuteInitialLayoutPass(target);
  112. impl.VerifySet(x => x.ClientSize = new Size(321, 432));
  113. }
  114. }
  115. [Fact]
  116. public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
  117. {
  118. using (PerspexLocator.EnterScope())
  119. {
  120. RegisterServices();
  121. var impl = new Mock<ITopLevelImpl>();
  122. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  123. var target = new TestTopLevel(impl.Object);
  124. LayoutManager.Instance.ExecuteLayoutPass();
  125. Assert.Equal(double.NaN, target.Width);
  126. Assert.Equal(double.NaN, target.Height);
  127. }
  128. }
  129. [Fact]
  130. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  131. {
  132. using (PerspexLocator.EnterScope())
  133. {
  134. RegisterServices();
  135. var impl = new Mock<ITopLevelImpl>();
  136. impl.SetupAllProperties();
  137. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  138. // The user has resized the window, so we can no longer auto-size.
  139. var target = new TestTopLevel(impl.Object);
  140. impl.Object.Resized(new Size(100, 200));
  141. Assert.Equal(100, target.Width);
  142. Assert.Equal(200, target.Height);
  143. }
  144. }
  145. [Fact]
  146. public void Activate_Should_Call_Impl_Activate()
  147. {
  148. using (PerspexLocator.EnterScope())
  149. {
  150. RegisterServices();
  151. var impl = new Mock<ITopLevelImpl>();
  152. var target = new TestTopLevel(impl.Object);
  153. target.Activate();
  154. impl.Verify(x => x.Activate());
  155. }
  156. }
  157. [Fact]
  158. public void Impl_Activate_Should_Call_Raise_Activated_Event()
  159. {
  160. using (PerspexLocator.EnterScope())
  161. {
  162. RegisterServices();
  163. var impl = new Mock<ITopLevelImpl>();
  164. impl.SetupAllProperties();
  165. bool raised = false;
  166. var target = new TestTopLevel(impl.Object);
  167. target.Activated += (s, e) => raised = true;
  168. impl.Object.Activated();
  169. Assert.True(raised);
  170. }
  171. }
  172. [Fact]
  173. public void Impl_Close_Should_Call_Raise_Closed_Event()
  174. {
  175. using (PerspexLocator.EnterScope())
  176. {
  177. RegisterServices();
  178. var impl = new Mock<ITopLevelImpl>();
  179. impl.SetupAllProperties();
  180. bool raised = false;
  181. var target = new TestTopLevel(impl.Object);
  182. target.Closed += (s, e) => raised = true;
  183. impl.Object.Closed();
  184. Assert.True(raised);
  185. }
  186. }
  187. [Fact]
  188. public void Impl_Deactivate_Should_Call_Raise_Activated_Event()
  189. {
  190. using (PerspexLocator.EnterScope())
  191. {
  192. RegisterServices();
  193. var impl = new Mock<ITopLevelImpl>();
  194. impl.SetupAllProperties();
  195. bool raised = false;
  196. var target = new TestTopLevel(impl.Object);
  197. target.Deactivated += (s, e) => raised = true;
  198. impl.Object.Deactivated();
  199. Assert.True(raised);
  200. }
  201. }
  202. [Fact]
  203. public void Impl_Input_Should_Pass_Input_To_InputManager()
  204. {
  205. using (PerspexLocator.EnterScope())
  206. {
  207. RegisterServices();
  208. var impl = new Mock<ITopLevelImpl>();
  209. impl.SetupAllProperties();
  210. var target = new TestTopLevel(impl.Object);
  211. var input = new RawKeyEventArgs(
  212. new Mock<IKeyboardDevice>().Object,
  213. 0,
  214. RawKeyEventType.KeyDown,
  215. Key.A, InputModifiers.None);
  216. impl.Object.Input(input);
  217. var inputManagerMock = Mock.Get(InputManager.Instance);
  218. inputManagerMock.Verify(x => x.Process(input));
  219. }
  220. }
  221. [Fact]
  222. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  223. {
  224. using (PerspexLocator.EnterScope())
  225. {
  226. RegisterServices();
  227. var impl = new Mock<ITopLevelImpl>();
  228. impl.SetupAllProperties();
  229. var target = new TestTopLevel(impl.Object);
  230. var child = new TestTopLevel(impl.Object);
  231. target.Template = CreateTemplate();
  232. target.Content = child;
  233. Assert.Throws<InvalidOperationException>(() => target.ApplyTemplate());
  234. }
  235. }
  236. private FuncControlTemplate<TestTopLevel> CreateTemplate()
  237. {
  238. return new FuncControlTemplate<TestTopLevel>(x =>
  239. new ContentPresenter
  240. {
  241. Name = "PART_ContentPresenter",
  242. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  243. });
  244. }
  245. private void RegisterServices()
  246. {
  247. var fixture = new Fixture().Customize(new AutoMoqCustomization());
  248. var l = PerspexLocator.CurrentMutable;
  249. var formattedText = fixture.Create<IFormattedTextImpl>();
  250. var globalStyles = new Mock<IGlobalStyles>();
  251. var layoutManager = fixture.Create<ILayoutManager>();
  252. var renderInterface = fixture.Create<IPlatformRenderInterface>();
  253. var renderManager = fixture.Create<IRenderQueueManager>();
  254. var windowImpl = new Mock<IWindowImpl>();
  255. var theme = new Styles();
  256. globalStyles.Setup(x => x.Styles).Returns(theme);
  257. PerspexLocator.CurrentMutable
  258. .Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
  259. .Bind<IFocusManager>().ToConstant(new Mock<IFocusManager>().Object)
  260. .Bind<IGlobalStyles>().ToConstant(globalStyles.Object)
  261. .Bind<ILayoutManager>().ToConstant(layoutManager)
  262. .Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
  263. .Bind<IRenderQueueManager>().ToConstant(renderManager)
  264. .Bind<IStyler>().ToConstant(new Styler());
  265. }
  266. private class TestTopLevel : TopLevel
  267. {
  268. public TestTopLevel(ITopLevelImpl impl)
  269. : base(impl)
  270. {
  271. }
  272. }
  273. }
  274. }