PageRenderTime 45ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/V4/PrismLibrary/Desktop/Prism.Tests/Commands/CompositeCommandFixture.cs

#
C# | 576 lines | 431 code | 127 blank | 18 comment | 4 complexity | 45db7930f57502a4e1a19cf27293b96c MD5 | raw file
  1. //===================================================================================
  2. // Microsoft patterns & practices
  3. // Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4. //===================================================================================
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8. // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9. // FITNESS FOR A PARTICULAR PURPOSE.
  10. //===================================================================================
  11. // The example companies, organizations, products, domain names,
  12. // e-mail addresses, logos, people, places, and events depicted
  13. // herein are fictitious. No association with any real company,
  14. // organization, product, domain name, email address, logo, person,
  15. // places, or events is intended or should be inferred.
  16. //===================================================================================
  17. using System;
  18. using System.Windows.Input;
  19. using Microsoft.Practices.Prism;
  20. using Microsoft.Practices.Prism.Commands;
  21. using Microsoft.VisualStudio.TestTools.UnitTesting;
  22. namespace Microsoft.Practices.Prism.Tests.Commands
  23. {
  24. [TestClass]
  25. public class CompositeCommandFixture
  26. {
  27. [TestMethod]
  28. public void RegisterACommandShouldRaiseCanExecuteEvent()
  29. {
  30. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  31. TestCommand testCommand = new TestCommand();
  32. multiCommand.RegisterCommand(new TestCommand());
  33. Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
  34. }
  35. [TestMethod]
  36. public void ShouldDelegateExecuteToSingleRegistrant()
  37. {
  38. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  39. TestCommand testCommand = new TestCommand();
  40. multiCommand.RegisterCommand(testCommand);
  41. Assert.IsFalse(testCommand.ExecuteCalled);
  42. multiCommand.Execute(null);
  43. Assert.IsTrue(testCommand.ExecuteCalled);
  44. }
  45. [TestMethod]
  46. public void ShouldDelegateExecuteToMultipleRegistrants()
  47. {
  48. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  49. TestCommand testCommandOne = new TestCommand();
  50. TestCommand testCommandTwo = new TestCommand();
  51. multiCommand.RegisterCommand(testCommandOne);
  52. multiCommand.RegisterCommand(testCommandTwo);
  53. Assert.IsFalse(testCommandOne.ExecuteCalled);
  54. Assert.IsFalse(testCommandTwo.ExecuteCalled);
  55. multiCommand.Execute(null);
  56. Assert.IsTrue(testCommandOne.ExecuteCalled);
  57. Assert.IsTrue(testCommandTwo.ExecuteCalled);
  58. }
  59. [TestMethod]
  60. public void ShouldDelegateCanExecuteToSingleRegistrant()
  61. {
  62. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  63. TestCommand testCommand = new TestCommand();
  64. multiCommand.RegisterCommand(testCommand);
  65. Assert.IsFalse(testCommand.CanExecuteCalled);
  66. multiCommand.CanExecute(null);
  67. Assert.IsTrue(testCommand.CanExecuteCalled);
  68. }
  69. [TestMethod]
  70. public void ShouldDelegateCanExecuteToMultipleRegistrants()
  71. {
  72. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  73. TestCommand testCommandOne = new TestCommand();
  74. TestCommand testCommandTwo = new TestCommand();
  75. multiCommand.RegisterCommand(testCommandOne);
  76. multiCommand.RegisterCommand(testCommandTwo);
  77. Assert.IsFalse(testCommandOne.CanExecuteCalled);
  78. Assert.IsFalse(testCommandTwo.CanExecuteCalled);
  79. multiCommand.CanExecute(null);
  80. Assert.IsTrue(testCommandOne.CanExecuteCalled);
  81. Assert.IsTrue(testCommandTwo.CanExecuteCalled);
  82. }
  83. [TestMethod]
  84. public void CanExecuteShouldReturnTrueIfAllRegistrantsTrue()
  85. {
  86. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  87. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  88. TestCommand testCommandTwo = new TestCommand() { CanExecuteValue = true };
  89. multiCommand.RegisterCommand(testCommandOne);
  90. multiCommand.RegisterCommand(testCommandTwo);
  91. Assert.IsTrue(multiCommand.CanExecute(null));
  92. }
  93. [TestMethod]
  94. public void CanExecuteShouldReturnFalseIfASingleRegistrantsFalse()
  95. {
  96. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  97. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  98. TestCommand testCommandTwo = new TestCommand() { CanExecuteValue = false };
  99. multiCommand.RegisterCommand(testCommandOne);
  100. multiCommand.RegisterCommand(testCommandTwo);
  101. Assert.IsFalse(multiCommand.CanExecute(null));
  102. }
  103. [TestMethod]
  104. public void ShouldReraiseCanExecuteChangedEvent()
  105. {
  106. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  107. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  108. Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
  109. multiCommand.RegisterCommand(testCommandOne);
  110. multiCommand.CanExecuteChangedRaised = false;
  111. testCommandOne.FireCanExecuteChanged();
  112. Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
  113. }
  114. [TestMethod]
  115. public void ShouldReraiseCanExecuteChangedEventAfterCollect()
  116. {
  117. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  118. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  119. Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
  120. multiCommand.RegisterCommand(testCommandOne);
  121. multiCommand.CanExecuteChangedRaised = false;
  122. GC.Collect();
  123. testCommandOne.FireCanExecuteChanged();
  124. Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
  125. }
  126. [TestMethod]
  127. public void ShouldReraiseDelegateCommandCanExecuteChangedEventAfterCollect()
  128. {
  129. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  130. DelegateCommand<object> delegateCommand = new DelegateCommand<object>(delegate { });
  131. Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
  132. multiCommand.RegisterCommand(delegateCommand);
  133. multiCommand.CanExecuteChangedRaised = false;
  134. GC.Collect();
  135. delegateCommand.RaiseCanExecuteChanged();
  136. Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
  137. }
  138. [TestMethod]
  139. public void UnregisterCommandRemovesFromExecuteDelegation()
  140. {
  141. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  142. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  143. multiCommand.RegisterCommand(testCommandOne);
  144. multiCommand.UnregisterCommand(testCommandOne);
  145. Assert.IsFalse(testCommandOne.ExecuteCalled);
  146. multiCommand.Execute(null);
  147. Assert.IsFalse(testCommandOne.ExecuteCalled);
  148. }
  149. [TestMethod]
  150. public void UnregisterCommandShouldRaiseCanExecuteEvent()
  151. {
  152. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  153. TestCommand testCommandOne = new TestCommand();
  154. multiCommand.RegisterCommand(testCommandOne);
  155. multiCommand.CanExecuteChangedRaised = false;
  156. multiCommand.UnregisterCommand(testCommandOne);
  157. Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
  158. }
  159. [TestMethod]
  160. public void ExecuteDoesNotThrowWhenAnExecuteCommandModifiesTheCommandsCollection()
  161. {
  162. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  163. SelfUnregisterableCommand commandOne = new SelfUnregisterableCommand(multiCommand);
  164. SelfUnregisterableCommand commandTwo = new SelfUnregisterableCommand(multiCommand);
  165. multiCommand.RegisterCommand(commandOne);
  166. multiCommand.RegisterCommand(commandTwo);
  167. multiCommand.Execute(null);
  168. Assert.IsTrue(commandOne.ExecutedCalled);
  169. Assert.IsTrue(commandTwo.ExecutedCalled);
  170. }
  171. [TestMethod]
  172. public void UnregisterCommandDisconnectsCanExecuteChangedDelegate()
  173. {
  174. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  175. TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
  176. multiCommand.RegisterCommand(testCommandOne);
  177. multiCommand.UnregisterCommand(testCommandOne);
  178. multiCommand.CanExecuteChangedRaised = false;
  179. testCommandOne.FireCanExecuteChanged();
  180. Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
  181. }
  182. [TestMethod, ExpectedException(typeof(DivideByZeroException))]
  183. public void ShouldBubbleException()
  184. {
  185. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  186. BadDivisionCommand testCommand = new BadDivisionCommand();
  187. multiCommand.RegisterCommand(testCommand);
  188. multiCommand.Execute(null);
  189. }
  190. [TestMethod]
  191. public void CanExecuteShouldReturnFalseWithNoCommandsRegistered()
  192. {
  193. TestableCompositeCommand multiCommand = new TestableCompositeCommand();
  194. Assert.IsFalse(multiCommand.CanExecute(null));
  195. }
  196. [TestMethod]
  197. public void MultiDispatchCommandExecutesActiveRegisteredCommands()
  198. {
  199. CompositeCommand activeAwareCommand = new CompositeCommand();
  200. MockActiveAwareCommand command = new MockActiveAwareCommand();
  201. command.IsActive = true;
  202. activeAwareCommand.RegisterCommand(command);
  203. activeAwareCommand.Execute(null);
  204. Assert.IsTrue(command.WasExecuted);
  205. }
  206. [TestMethod]
  207. public void MultiDispatchCommandDoesNotExecutesInactiveRegisteredCommands()
  208. {
  209. CompositeCommand activeAwareCommand = new CompositeCommand(true);
  210. MockActiveAwareCommand command = new MockActiveAwareCommand();
  211. command.IsActive = false;
  212. activeAwareCommand.RegisterCommand(command);
  213. activeAwareCommand.Execute(null);
  214. Assert.IsFalse(command.WasExecuted);
  215. }
  216. [TestMethod]
  217. public void DispatchCommandDoesNotIncludeInactiveRegisteredCommandInVoting()
  218. {
  219. CompositeCommand activeAwareCommand = new CompositeCommand(true);
  220. MockActiveAwareCommand command = new MockActiveAwareCommand();
  221. activeAwareCommand.RegisterCommand(command);
  222. command.IsValid = true;
  223. command.IsActive = false;
  224. Assert.IsFalse(activeAwareCommand.CanExecute(null), "Registered Click is inactive so should not participate in CanExecute vote");
  225. command.IsActive = true;
  226. Assert.IsTrue(activeAwareCommand.CanExecute(null));
  227. command.IsValid = false;
  228. Assert.IsFalse(activeAwareCommand.CanExecute(null));
  229. }
  230. [TestMethod]
  231. public void DispatchCommandShouldIgnoreInactiveCommandsInCanExecuteVote()
  232. {
  233. CompositeCommand activeAwareCommand = new CompositeCommand(true);
  234. MockActiveAwareCommand commandOne = new MockActiveAwareCommand() { IsActive = false, IsValid = false };
  235. MockActiveAwareCommand commandTwo = new MockActiveAwareCommand() { IsActive = true, IsValid = true };
  236. activeAwareCommand.RegisterCommand(commandOne);
  237. activeAwareCommand.RegisterCommand(commandTwo);
  238. Assert.IsTrue(activeAwareCommand.CanExecute(null));
  239. }
  240. [TestMethod]
  241. public void ActivityCausesActiveAwareCommandToRequeryCanExecute()
  242. {
  243. CompositeCommand activeAwareCommand = new CompositeCommand(true);
  244. MockActiveAwareCommand command = new MockActiveAwareCommand();
  245. activeAwareCommand.RegisterCommand(command);
  246. command.IsActive = true;
  247. bool globalCanExecuteChangeFired = false;
  248. activeAwareCommand.CanExecuteChanged += delegate
  249. {
  250. globalCanExecuteChangeFired = true;
  251. };
  252. Assert.IsFalse(globalCanExecuteChangeFired);
  253. command.IsActive = false;
  254. Assert.IsTrue(globalCanExecuteChangeFired);
  255. }
  256. [TestMethod]
  257. public void ShouldNotMonitorActivityIfUseActiveMonitoringFalse()
  258. {
  259. var mockCommand = new MockActiveAwareCommand();
  260. mockCommand.IsValid = true;
  261. mockCommand.IsActive = true;
  262. var nonActiveAwareCompositeCommand = new CompositeCommand(false);
  263. bool canExecuteChangedRaised = false;
  264. nonActiveAwareCompositeCommand.RegisterCommand(mockCommand);
  265. nonActiveAwareCompositeCommand.CanExecuteChanged += delegate
  266. {
  267. canExecuteChangedRaised = true;
  268. };
  269. mockCommand.IsActive = false;
  270. Assert.IsFalse(canExecuteChangedRaised);
  271. nonActiveAwareCompositeCommand.Execute(null);
  272. Assert.IsTrue(mockCommand.WasExecuted);
  273. }
  274. [TestMethod]
  275. public void ShouldIgnoreChangesToIsActiveDuringExecution()
  276. {
  277. var firstCommand = new MockActiveAwareCommand { IsActive = true };
  278. var secondCommand = new MockActiveAwareCommand { IsActive = true };
  279. // During execution set the second command to inactive, this should not affect the currently
  280. // executed selection.
  281. firstCommand.ExecuteAction += new Action<object>((object parameter) => secondCommand.IsActive = false);
  282. var compositeCommand = new CompositeCommand(true);
  283. compositeCommand.RegisterCommand(firstCommand);
  284. compositeCommand.RegisterCommand(secondCommand);
  285. compositeCommand.Execute(null);
  286. Assert.IsTrue(secondCommand.WasExecuted);
  287. }
  288. [TestMethod]
  289. [ExpectedException(typeof(ArgumentException))]
  290. public void RegisteringCommandInItselfThrows()
  291. {
  292. var compositeCommand = new CompositeCommand();
  293. compositeCommand.RegisterCommand(compositeCommand);
  294. }
  295. [TestMethod]
  296. [ExpectedException(typeof(InvalidOperationException))]
  297. public void RegisteringCommandTwiceThrows()
  298. {
  299. var compositeCommand = new CompositeCommand();
  300. var duplicateCommand = new TestCommand();
  301. compositeCommand.RegisterCommand(duplicateCommand);
  302. compositeCommand.RegisterCommand(duplicateCommand);
  303. }
  304. #if SILVERLIGHT
  305. [TestMethod]
  306. public void ShouldKeepStrongReferenceToOnCanExecuteChangedHandlers()
  307. {
  308. var command = new TestableCompositeCommand();
  309. var handlers = new CanExecutChangeHandler();
  310. var weakHandlerRef = new WeakReference(handlers);
  311. Assert.IsTrue(weakHandlerRef.IsAlive, "FirstOne");
  312. command.CanExecuteChanged += handlers.CanExecuteChangeHandler;
  313. handlers = null;
  314. GC.Collect();
  315. Assert.IsTrue(weakHandlerRef.IsAlive);
  316. Assert.IsNotNull(command); // Only here to ensure command survives optimizations and the GC.Collect
  317. }
  318. #else
  319. [TestMethod]
  320. public void ShouldKeepWeakReferenceToOnCanExecuteChangedHandlers()
  321. {
  322. var command = new TestableCompositeCommand();
  323. var handlers = new CanExecutChangeHandler();
  324. var weakHandlerRef = new WeakReference(handlers);
  325. command.CanExecuteChanged += handlers.CanExecuteChangeHandler;
  326. handlers = null;
  327. GC.Collect();
  328. Assert.IsFalse(weakHandlerRef.IsAlive);
  329. Assert.IsNotNull(command); // Only here to ensure command survives optimizations and the GC.Collect
  330. }
  331. #endif
  332. private class CanExecutChangeHandler
  333. {
  334. private int callCount = 0;
  335. public void CanExecuteChangeHandler(object sender, EventArgs e)
  336. {
  337. callCount++;
  338. }
  339. }
  340. }
  341. internal class MockActiveAwareCommand : IActiveAware, ICommand
  342. {
  343. private bool _isActive;
  344. public Action<object> ExecuteAction;
  345. #region IActiveAware Members
  346. public bool IsActive
  347. {
  348. get { return _isActive; }
  349. set
  350. {
  351. if (_isActive != value)
  352. {
  353. _isActive = value;
  354. OnActiveChanged(this, EventArgs.Empty);
  355. }
  356. }
  357. }
  358. public event EventHandler IsActiveChanged = delegate { };
  359. #endregion
  360. virtual protected void OnActiveChanged(object sender, EventArgs e)
  361. {
  362. IsActiveChanged(sender, e);
  363. }
  364. public bool WasExecuted { get; set; }
  365. public bool IsValid { get; set; }
  366. #region ICommand Members
  367. public bool CanExecute(object parameter)
  368. {
  369. return IsValid;
  370. }
  371. public event EventHandler CanExecuteChanged = delegate { };
  372. public void Execute(object parameter)
  373. {
  374. WasExecuted = true;
  375. if (ExecuteAction != null)
  376. ExecuteAction(parameter);
  377. }
  378. #endregion
  379. }
  380. internal class TestableCompositeCommand : CompositeCommand
  381. {
  382. public bool CanExecuteChangedRaised;
  383. private EventHandler handler;
  384. public TestableCompositeCommand()
  385. {
  386. this.handler = ((sender, e) => CanExecuteChangedRaised = true);
  387. CanExecuteChanged += this.handler;
  388. }
  389. }
  390. internal class TestCommand : ICommand
  391. {
  392. public bool CanExecuteCalled { get; set; }
  393. public bool ExecuteCalled { get; set; }
  394. public int ExecuteCallCount { get; set; }
  395. public bool CanExecuteValue = true;
  396. public void FireCanExecuteChanged()
  397. {
  398. CanExecuteChanged(this, EventArgs.Empty);
  399. }
  400. #region ICommand Members
  401. public bool CanExecute(object parameter)
  402. {
  403. CanExecuteCalled = true;
  404. return CanExecuteValue;
  405. }
  406. public event EventHandler CanExecuteChanged = delegate { };
  407. public void Execute(object parameter)
  408. {
  409. ExecuteCalled = true;
  410. ExecuteCallCount += 1;
  411. }
  412. #endregion
  413. }
  414. internal class BadDivisionCommand : ICommand
  415. {
  416. #region ICommand Members
  417. public bool CanExecute(object parameter)
  418. {
  419. return true;
  420. }
  421. public event EventHandler CanExecuteChanged;
  422. public void Execute(object parameter)
  423. {
  424. throw new DivideByZeroException("Test Divide By Zero");
  425. }
  426. #endregion
  427. }
  428. internal class SelfUnregisterableCommand : ICommand
  429. {
  430. public CompositeCommand Command;
  431. public bool ExecutedCalled = false;
  432. public SelfUnregisterableCommand(CompositeCommand command)
  433. {
  434. Command = command;
  435. }
  436. #region ICommand Members
  437. public bool CanExecute(object parameter)
  438. {
  439. throw new NotImplementedException();
  440. }
  441. public event EventHandler CanExecuteChanged;
  442. public void Execute(object parameter)
  443. {
  444. Command.UnregisterCommand(this);
  445. ExecutedCalled = true;
  446. }
  447. #endregion
  448. }
  449. }