PageRenderTime 40ms CodeModel.GetById 19ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 1ms

/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//===================================================================================
 17using System;
 18using System.Windows.Input;
 19using Microsoft.Practices.Prism;
 20using Microsoft.Practices.Prism.Commands;
 21using Microsoft.VisualStudio.TestTools.UnitTesting;
 22
 23namespace Microsoft.Practices.Prism.Tests.Commands
 24{
 25    [TestClass]
 26    public class CompositeCommandFixture
 27    {
 28        [TestMethod]
 29        public void RegisterACommandShouldRaiseCanExecuteEvent()
 30        {
 31            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
 32            TestCommand testCommand = new TestCommand();
 33
 34            multiCommand.RegisterCommand(new TestCommand());
 35            Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
 36        }
 37
 38        [TestMethod]
 39        public void ShouldDelegateExecuteToSingleRegistrant()
 40        {
 41            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
 42            TestCommand testCommand = new TestCommand();
 43
 44            multiCommand.RegisterCommand(testCommand);
 45
 46            Assert.IsFalse(testCommand.ExecuteCalled);
 47            multiCommand.Execute(null);
 48            Assert.IsTrue(testCommand.ExecuteCalled);
 49        }
 50
 51        [TestMethod]
 52        public void ShouldDelegateExecuteToMultipleRegistrants()
 53        {
 54            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
 55            TestCommand testCommandOne = new TestCommand();
 56            TestCommand testCommandTwo = new TestCommand();
 57
 58            multiCommand.RegisterCommand(testCommandOne);
 59            multiCommand.RegisterCommand(testCommandTwo);
 60
 61            Assert.IsFalse(testCommandOne.ExecuteCalled);
 62            Assert.IsFalse(testCommandTwo.ExecuteCalled);
 63            multiCommand.Execute(null);
 64            Assert.IsTrue(testCommandOne.ExecuteCalled);
 65            Assert.IsTrue(testCommandTwo.ExecuteCalled);
 66        }
 67
 68        [TestMethod]
 69        public void ShouldDelegateCanExecuteToSingleRegistrant()
 70        {
 71            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
 72            TestCommand testCommand = new TestCommand();
 73
 74            multiCommand.RegisterCommand(testCommand);
 75
 76            Assert.IsFalse(testCommand.CanExecuteCalled);
 77            multiCommand.CanExecute(null);
 78            Assert.IsTrue(testCommand.CanExecuteCalled);
 79        }
 80
 81        [TestMethod]
 82        public void ShouldDelegateCanExecuteToMultipleRegistrants()
 83        {
 84            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
 85            TestCommand testCommandOne = new TestCommand();
 86            TestCommand testCommandTwo = new TestCommand();
 87
 88            multiCommand.RegisterCommand(testCommandOne);
 89            multiCommand.RegisterCommand(testCommandTwo);
 90
 91            Assert.IsFalse(testCommandOne.CanExecuteCalled);
 92            Assert.IsFalse(testCommandTwo.CanExecuteCalled);
 93            multiCommand.CanExecute(null);
 94            Assert.IsTrue(testCommandOne.CanExecuteCalled);
 95            Assert.IsTrue(testCommandTwo.CanExecuteCalled);
 96        }
 97
 98        [TestMethod]
 99        public void CanExecuteShouldReturnTrueIfAllRegistrantsTrue()
100        {
101            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
102            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
103            TestCommand testCommandTwo = new TestCommand() { CanExecuteValue = true };
104
105            multiCommand.RegisterCommand(testCommandOne);
106            multiCommand.RegisterCommand(testCommandTwo);
107
108            Assert.IsTrue(multiCommand.CanExecute(null));
109        }
110
111        [TestMethod]
112        public void CanExecuteShouldReturnFalseIfASingleRegistrantsFalse()
113        {
114            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
115            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
116            TestCommand testCommandTwo = new TestCommand() { CanExecuteValue = false };
117
118            multiCommand.RegisterCommand(testCommandOne);
119            multiCommand.RegisterCommand(testCommandTwo);
120
121            Assert.IsFalse(multiCommand.CanExecute(null));
122        }
123
124        [TestMethod]
125        public void ShouldReraiseCanExecuteChangedEvent()
126        {
127            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
128            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
129
130            Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
131            multiCommand.RegisterCommand(testCommandOne);
132            multiCommand.CanExecuteChangedRaised = false;
133
134            testCommandOne.FireCanExecuteChanged();
135            Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
136        }
137
138        [TestMethod]
139        public void ShouldReraiseCanExecuteChangedEventAfterCollect()
140        {
141            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
142            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
143
144            Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
145            multiCommand.RegisterCommand(testCommandOne);
146            multiCommand.CanExecuteChangedRaised = false;
147
148            GC.Collect();
149
150            testCommandOne.FireCanExecuteChanged();
151            Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
152        }
153
154        [TestMethod]
155        public void ShouldReraiseDelegateCommandCanExecuteChangedEventAfterCollect()
156        {
157            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
158            DelegateCommand<object> delegateCommand = new DelegateCommand<object>(delegate { });
159
160            Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
161            multiCommand.RegisterCommand(delegateCommand);
162            multiCommand.CanExecuteChangedRaised = false;
163
164            GC.Collect();
165
166            delegateCommand.RaiseCanExecuteChanged();
167            Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
168        }
169
170        [TestMethod]
171        public void UnregisterCommandRemovesFromExecuteDelegation()
172        {
173            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
174            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
175
176            multiCommand.RegisterCommand(testCommandOne);
177            multiCommand.UnregisterCommand(testCommandOne);
178
179            Assert.IsFalse(testCommandOne.ExecuteCalled);
180            multiCommand.Execute(null);
181            Assert.IsFalse(testCommandOne.ExecuteCalled);
182        }
183
184        [TestMethod]
185        public void UnregisterCommandShouldRaiseCanExecuteEvent()
186        {
187            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
188            TestCommand testCommandOne = new TestCommand();
189
190            multiCommand.RegisterCommand(testCommandOne);
191            multiCommand.CanExecuteChangedRaised = false;
192            multiCommand.UnregisterCommand(testCommandOne);
193
194            Assert.IsTrue(multiCommand.CanExecuteChangedRaised);
195        }
196
197        [TestMethod]
198        public void ExecuteDoesNotThrowWhenAnExecuteCommandModifiesTheCommandsCollection()
199        {
200            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
201            SelfUnregisterableCommand commandOne = new SelfUnregisterableCommand(multiCommand);
202            SelfUnregisterableCommand commandTwo = new SelfUnregisterableCommand(multiCommand);
203
204            multiCommand.RegisterCommand(commandOne);
205            multiCommand.RegisterCommand(commandTwo);
206
207            multiCommand.Execute(null);
208
209            Assert.IsTrue(commandOne.ExecutedCalled);
210            Assert.IsTrue(commandTwo.ExecutedCalled);
211        }
212
213        [TestMethod]
214        public void UnregisterCommandDisconnectsCanExecuteChangedDelegate()
215        {
216            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
217            TestCommand testCommandOne = new TestCommand() { CanExecuteValue = true };
218
219            multiCommand.RegisterCommand(testCommandOne);
220            multiCommand.UnregisterCommand(testCommandOne);
221            multiCommand.CanExecuteChangedRaised = false;
222            testCommandOne.FireCanExecuteChanged();
223            Assert.IsFalse(multiCommand.CanExecuteChangedRaised);
224        }
225
226        [TestMethod, ExpectedException(typeof(DivideByZeroException))]
227        public void ShouldBubbleException()
228        {
229            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
230            BadDivisionCommand testCommand = new BadDivisionCommand();
231
232            multiCommand.RegisterCommand(testCommand);
233            multiCommand.Execute(null);
234        }
235
236        [TestMethod]
237        public void CanExecuteShouldReturnFalseWithNoCommandsRegistered()
238        {
239            TestableCompositeCommand multiCommand = new TestableCompositeCommand();
240            Assert.IsFalse(multiCommand.CanExecute(null));
241        }
242
243        [TestMethod]
244        public void MultiDispatchCommandExecutesActiveRegisteredCommands()
245        {
246            CompositeCommand activeAwareCommand = new CompositeCommand();
247            MockActiveAwareCommand command = new MockActiveAwareCommand();
248            command.IsActive = true;
249            activeAwareCommand.RegisterCommand(command);
250
251            activeAwareCommand.Execute(null);
252
253            Assert.IsTrue(command.WasExecuted);
254        }
255
256        [TestMethod]
257        public void MultiDispatchCommandDoesNotExecutesInactiveRegisteredCommands()
258        {
259            CompositeCommand activeAwareCommand = new CompositeCommand(true);
260            MockActiveAwareCommand command = new MockActiveAwareCommand();
261            command.IsActive = false;
262            activeAwareCommand.RegisterCommand(command);
263
264            activeAwareCommand.Execute(null);
265
266            Assert.IsFalse(command.WasExecuted);
267        }
268
269        [TestMethod]
270        public void DispatchCommandDoesNotIncludeInactiveRegisteredCommandInVoting()
271        {
272            CompositeCommand activeAwareCommand = new CompositeCommand(true);
273            MockActiveAwareCommand command = new MockActiveAwareCommand();
274            activeAwareCommand.RegisterCommand(command);
275            command.IsValid = true;
276            command.IsActive = false;
277
278            Assert.IsFalse(activeAwareCommand.CanExecute(null), "Registered Click is inactive so should not participate in CanExecute vote");
279
280            command.IsActive = true;
281
282            Assert.IsTrue(activeAwareCommand.CanExecute(null));
283
284            command.IsValid = false;
285
286            Assert.IsFalse(activeAwareCommand.CanExecute(null));
287
288        }
289
290        [TestMethod]
291        public void DispatchCommandShouldIgnoreInactiveCommandsInCanExecuteVote()
292        {
293            CompositeCommand activeAwareCommand = new CompositeCommand(true);
294            MockActiveAwareCommand commandOne = new MockActiveAwareCommand() { IsActive = false, IsValid = false };
295            MockActiveAwareCommand commandTwo = new MockActiveAwareCommand() { IsActive = true, IsValid = true };
296
297            activeAwareCommand.RegisterCommand(commandOne);
298            activeAwareCommand.RegisterCommand(commandTwo);
299
300            Assert.IsTrue(activeAwareCommand.CanExecute(null));
301        }
302
303        [TestMethod]
304        public void ActivityCausesActiveAwareCommandToRequeryCanExecute()
305        {
306            CompositeCommand activeAwareCommand = new CompositeCommand(true);
307            MockActiveAwareCommand command = new MockActiveAwareCommand();
308            activeAwareCommand.RegisterCommand(command);
309            command.IsActive = true;
310
311            bool globalCanExecuteChangeFired = false;
312            activeAwareCommand.CanExecuteChanged += delegate
313                                                        {
314                                                            globalCanExecuteChangeFired = true;
315                                                        };
316
317            Assert.IsFalse(globalCanExecuteChangeFired);
318            command.IsActive = false;
319            Assert.IsTrue(globalCanExecuteChangeFired);
320        }
321
322        [TestMethod]
323        public void ShouldNotMonitorActivityIfUseActiveMonitoringFalse()
324        {
325            var mockCommand = new MockActiveAwareCommand();
326            mockCommand.IsValid = true;
327            mockCommand.IsActive = true;
328            var nonActiveAwareCompositeCommand = new CompositeCommand(false);
329            bool canExecuteChangedRaised = false;
330            nonActiveAwareCompositeCommand.RegisterCommand(mockCommand);
331            nonActiveAwareCompositeCommand.CanExecuteChanged += delegate
332            {
333                canExecuteChangedRaised = true;
334            };
335
336            mockCommand.IsActive = false;
337
338            Assert.IsFalse(canExecuteChangedRaised);
339
340            nonActiveAwareCompositeCommand.Execute(null);
341
342            Assert.IsTrue(mockCommand.WasExecuted);
343        }
344
345        [TestMethod]
346        public void ShouldIgnoreChangesToIsActiveDuringExecution()
347        {
348            var firstCommand = new MockActiveAwareCommand { IsActive = true };
349            var secondCommand = new MockActiveAwareCommand { IsActive = true };
350
351            // During execution set the second command to inactive, this should not affect the currently
352            // executed selection.  
353            firstCommand.ExecuteAction += new Action<object>((object parameter) => secondCommand.IsActive = false);
354
355            var compositeCommand = new CompositeCommand(true);
356
357            compositeCommand.RegisterCommand(firstCommand);
358            compositeCommand.RegisterCommand(secondCommand);
359
360            compositeCommand.Execute(null);
361
362            Assert.IsTrue(secondCommand.WasExecuted);
363        }
364
365        [TestMethod]
366        [ExpectedException(typeof(ArgumentException))]
367        public void RegisteringCommandInItselfThrows()
368        {
369            var compositeCommand = new CompositeCommand();
370
371            compositeCommand.RegisterCommand(compositeCommand);
372        }
373
374        [TestMethod]
375        [ExpectedException(typeof(InvalidOperationException))]
376        public void RegisteringCommandTwiceThrows()
377        {
378            var compositeCommand = new CompositeCommand();
379            var duplicateCommand = new TestCommand();
380            compositeCommand.RegisterCommand(duplicateCommand);
381
382            compositeCommand.RegisterCommand(duplicateCommand);
383        }
384
385#if SILVERLIGHT
386        [TestMethod]
387        public void ShouldKeepStrongReferenceToOnCanExecuteChangedHandlers()
388        {
389            var command = new TestableCompositeCommand();
390
391            var handlers = new CanExecutChangeHandler();
392
393            var weakHandlerRef = new WeakReference(handlers);
394            Assert.IsTrue(weakHandlerRef.IsAlive, "FirstOne");
395
396            command.CanExecuteChanged += handlers.CanExecuteChangeHandler;
397
398            handlers = null;
399
400            GC.Collect();
401
402            Assert.IsTrue(weakHandlerRef.IsAlive);
403            Assert.IsNotNull(command); // Only here to ensure command survives optimizations and the GC.Collect
404        }
405#else
406        [TestMethod]
407        public void ShouldKeepWeakReferenceToOnCanExecuteChangedHandlers()
408        {
409            var command = new TestableCompositeCommand();
410
411            var handlers = new CanExecutChangeHandler();
412            var weakHandlerRef = new WeakReference(handlers);
413            command.CanExecuteChanged += handlers.CanExecuteChangeHandler;
414            handlers = null;
415
416            GC.Collect();
417
418            Assert.IsFalse(weakHandlerRef.IsAlive);
419            Assert.IsNotNull(command); // Only here to ensure command survives optimizations and the GC.Collect
420        }
421#endif
422
423        private class CanExecutChangeHandler
424        {
425            private int callCount = 0;
426
427            public void CanExecuteChangeHandler(object sender, EventArgs e)
428            {
429                callCount++;
430            }
431        }
432    }
433
434    internal class MockActiveAwareCommand : IActiveAware, ICommand
435    {
436        private bool _isActive;
437
438        public Action<object> ExecuteAction;
439
440
441        #region IActiveAware Members
442
443        public bool IsActive
444        {
445            get { return _isActive; }
446            set
447            {
448                if (_isActive != value)
449                {
450                    _isActive = value;
451                    OnActiveChanged(this, EventArgs.Empty);
452                }
453            }
454        }
455
456        public event EventHandler IsActiveChanged = delegate { };
457        #endregion
458
459        virtual protected void OnActiveChanged(object sender, EventArgs e)
460        {
461            IsActiveChanged(sender, e);
462        }
463
464        public bool WasExecuted { get; set; }
465        public bool IsValid { get; set; }
466
467
468        #region ICommand Members
469
470        public bool CanExecute(object parameter)
471        {
472            return IsValid;
473        }
474
475        public event EventHandler CanExecuteChanged = delegate { };
476
477        public void Execute(object parameter)
478        {
479            WasExecuted = true;
480            if (ExecuteAction != null)
481                ExecuteAction(parameter);
482        }
483
484        #endregion
485    }
486
487    internal class TestableCompositeCommand : CompositeCommand
488    {
489        public bool CanExecuteChangedRaised;
490        private EventHandler handler;
491
492        public TestableCompositeCommand()
493        {
494            this.handler = ((sender, e) => CanExecuteChangedRaised = true);
495            CanExecuteChanged += this.handler;
496        }
497    }
498
499    internal class TestCommand : ICommand
500    {
501        public bool CanExecuteCalled { get; set; }
502        public bool ExecuteCalled { get; set; }
503        public int ExecuteCallCount { get; set; }
504
505        public bool CanExecuteValue = true;
506
507        public void FireCanExecuteChanged()
508        {
509            CanExecuteChanged(this, EventArgs.Empty);
510        }
511        #region ICommand Members
512
513        public bool CanExecute(object parameter)
514        {
515            CanExecuteCalled = true;
516            return CanExecuteValue;
517        }
518
519        public event EventHandler CanExecuteChanged = delegate { };
520
521        public void Execute(object parameter)
522        {
523            ExecuteCalled = true;
524            ExecuteCallCount += 1;
525        }
526
527        #endregion
528    }
529
530    internal class BadDivisionCommand : ICommand
531    {
532        #region ICommand Members
533
534        public bool CanExecute(object parameter)
535        {
536            return true;
537        }
538
539        public event EventHandler CanExecuteChanged;
540
541        public void Execute(object parameter)
542        {
543            throw new DivideByZeroException("Test Divide By Zero");
544        }
545
546        #endregion
547    }
548
549    internal class SelfUnregisterableCommand : ICommand
550    {
551        public CompositeCommand Command;
552        public bool ExecutedCalled = false;
553
554        public SelfUnregisterableCommand(CompositeCommand command)
555        {
556            Command = command;
557        }
558
559        #region ICommand Members
560
561        public bool CanExecute(object parameter)
562        {
563            throw new NotImplementedException();
564        }
565
566        public event EventHandler CanExecuteChanged;
567
568        public void Execute(object parameter)
569        {
570            Command.UnregisterCommand(this);
571            ExecutedCalled = true;
572        }
573
574        #endregion
575    }
576}