TopLevelTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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(target.LayoutManager);
  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. target.LayoutManager.ExecuteLayoutPass();
  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. target.LayoutManager.ExecuteLayoutPass();
  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. target.LayoutManager.ExecuteLayoutPass();
  125. Assert.Equal(double.NaN, target.Width);
  126. Assert.Equal(double.NaN, target.Height);
  127. }
  128. }
  129. [Fact]
  130. public void Render_Should_Be_Scheduled_After_Layout_Pass()
  131. {
  132. using (PerspexLocator.EnterScope())
  133. {
  134. RegisterServices();
  135. var completed = new Subject<Unit>();
  136. var layoutManagerMock = Mock.Get(PerspexLocator.Current.GetService<ILayoutManager>());
  137. layoutManagerMock.Setup(x => x.LayoutCompleted).Returns(completed);
  138. var impl = new Mock<ITopLevelImpl>();
  139. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  140. var target = new TestTopLevel(impl.Object);
  141. completed.OnNext(Unit.Default);
  142. var renderManagerMock = Mock.Get(PerspexLocator.Current.GetService<IRenderQueueManager>());
  143. renderManagerMock.Verify(x => x.InvalidateRender(target));
  144. }
  145. }
  146. [Fact]
  147. public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
  148. {
  149. using (PerspexLocator.EnterScope())
  150. {
  151. RegisterServices();
  152. var impl = new Mock<ITopLevelImpl>();
  153. impl.SetupAllProperties();
  154. impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
  155. // The user has resized the window, so we can no longer auto-size.
  156. var target = new TestTopLevel(impl.Object);
  157. impl.Object.Resized(new Size(100, 200));
  158. Assert.Equal(100, target.Width);
  159. Assert.Equal(200, target.Height);
  160. }
  161. }
  162. [Fact]
  163. public void Activate_Should_Call_Impl_Activate()
  164. {
  165. using (PerspexLocator.EnterScope())
  166. {
  167. RegisterServices();
  168. var impl = new Mock<ITopLevelImpl>();
  169. var target = new TestTopLevel(impl.Object);
  170. target.Activate();
  171. impl.Verify(x => x.Activate());
  172. }
  173. }
  174. [Fact]
  175. public void Impl_Activate_Should_Call_Raise_Activated_Event()
  176. {
  177. using (PerspexLocator.EnterScope())
  178. {
  179. RegisterServices();
  180. var impl = new Mock<ITopLevelImpl>();
  181. impl.SetupAllProperties();
  182. bool raised = false;
  183. var target = new TestTopLevel(impl.Object);
  184. target.Activated += (s, e) => raised = true;
  185. impl.Object.Activated();
  186. Assert.True(raised);
  187. }
  188. }
  189. [Fact]
  190. public void Impl_Close_Should_Call_Raise_Closed_Event()
  191. {
  192. using (PerspexLocator.EnterScope())
  193. {
  194. RegisterServices();
  195. var impl = new Mock<ITopLevelImpl>();
  196. impl.SetupAllProperties();
  197. bool raised = false;
  198. var target = new TestTopLevel(impl.Object);
  199. target.Closed += (s, e) => raised = true;
  200. impl.Object.Closed();
  201. Assert.True(raised);
  202. }
  203. }
  204. [Fact]
  205. public void Impl_Deactivate_Should_Call_Raise_Activated_Event()
  206. {
  207. using (PerspexLocator.EnterScope())
  208. {
  209. RegisterServices();
  210. var impl = new Mock<ITopLevelImpl>();
  211. impl.SetupAllProperties();
  212. bool raised = false;
  213. var target = new TestTopLevel(impl.Object);
  214. target.Deactivated += (s, e) => raised = true;
  215. impl.Object.Deactivated();
  216. Assert.True(raised);
  217. }
  218. }
  219. [Fact]
  220. public void Impl_Input_Should_Pass_Input_To_InputManager()
  221. {
  222. using (PerspexLocator.EnterScope())
  223. {
  224. RegisterServices();
  225. var impl = new Mock<ITopLevelImpl>();
  226. impl.SetupAllProperties();
  227. var target = new TestTopLevel(impl.Object);
  228. var input = new RawKeyEventArgs(
  229. new Mock<IKeyboardDevice>().Object,
  230. 0,
  231. RawKeyEventType.KeyDown,
  232. Key.A, InputModifiers.None);
  233. impl.Object.Input(input);
  234. var inputManagerMock = Mock.Get(InputManager.Instance);
  235. inputManagerMock.Verify(x => x.Process(input));
  236. }
  237. }
  238. [Fact]
  239. public void Adding_Top_Level_As_Child_Should_Throw_Exception()
  240. {
  241. using (PerspexLocator.EnterScope())
  242. {
  243. RegisterServices();
  244. var impl = new Mock<ITopLevelImpl>();
  245. impl.SetupAllProperties();
  246. var target = new TestTopLevel(impl.Object);
  247. var child = new TestTopLevel(impl.Object);
  248. target.Template = CreateTemplate();
  249. target.Content = child;
  250. Assert.Throws<InvalidOperationException>(() => target.ApplyTemplate());
  251. }
  252. }
  253. private ControlTemplate<TestTopLevel> CreateTemplate()
  254. {
  255. return new ControlTemplate<TestTopLevel>(x =>
  256. new ContentPresenter
  257. {
  258. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  259. });
  260. }
  261. private void RegisterServices()
  262. {
  263. var fixture = new Fixture().Customize(new AutoMoqCustomization());
  264. var l = PerspexLocator.CurrentMutable;
  265. var formattedText = fixture.Create<IFormattedTextImpl>();
  266. var globalStyles = new Mock<IGlobalStyles>();
  267. var layoutManager = fixture.Create<ILayoutManager>();
  268. var renderInterface = fixture.Create<IPlatformRenderInterface>();
  269. var renderManager = fixture.Create<IRenderQueueManager>();
  270. var windowImpl = new Mock<IWindowImpl>();
  271. var theme = new Styles();
  272. globalStyles.Setup(x => x.Styles).Returns(theme);
  273. PerspexLocator.CurrentMutable
  274. .Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
  275. .Bind<IFocusManager>().ToConstant(new Mock<IFocusManager>().Object)
  276. .Bind<IGlobalStyles>().ToConstant(globalStyles.Object)
  277. .Bind<ILayoutManager>().ToConstant(layoutManager)
  278. .Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
  279. .Bind<IRenderQueueManager>().ToConstant(renderManager)
  280. .Bind<IStyler>().ToConstant(new Styler());
  281. }
  282. private class TestTopLevel : TopLevel
  283. {
  284. public TestTopLevel(ITopLevelImpl impl)
  285. : base(impl)
  286. {
  287. }
  288. }
  289. }
  290. }