Click here to Skip to main content
12,507,674 members (50,422 online)
Click here to Skip to main content

Stats

29.5K views
281 downloads
47 bookmarked
Posted

MVP Dependency Chaining Framework

, 14 Oct 2007
An MVP framework that generates an intercepting filter layer consisting of a linked list of presenters by parsing a set of dependency rules.
MVPChainingFactory_demo
App_Data
Bin
MVPChainingFactory.dll
MVPChainingFactory.pdb
MVPChainingFactory.Web.dll
MVPChainingFactory.Web.dll.refresh
MVPChainingFactory.Web.pdb
StubPresentersUsecase1.dll
StubPresentersUsecase1.dll.refresh
StubPresentersUsecase1.pdb
SampleWebsite.suo
MVPChainingFactory_src
MVPChainingFactory.gpState
MVPChainingFactory.suo
MVPChainingFactory.Tests
bin
Debug
Rhino.Mocks.dll
Release
MVPChainingFactory.Tests.csproj.user
obj
Debug
Refactor
TempPE
Release
build.force
Refactor
TempPE
Properties
StubPresentersUsecase1
bin
Debug
Release
MVPChainingFactory.dll
MVPChainingFactory.pdb
StubPresentersUsecase1.dll
StubPresentersUsecase1.pdb
obj
Debug
Refactor
StubPresentersUsecase1.dll
TempPE
Release
build.force
Refactor
StubPresentersUsecase1.dll
ResolveAssemblyReference.cache
StubPresentersUsecase1.dll
StubPresentersUsecase1.pdb
TempPE
Properties
StubPresentersUsecase2
bin
Debug
Release
obj
Debug
Refactor
StubPresentersUsecase2.dll
TempPE
Release
build.force
Refactor
StubPresentersUsecase2.dll
TempPE
Properties
StubPresentersUsecase3
bin
Debug
Release
obj
Debug
Refactor
StubPresentersUsecase3.dll
TempPE
Release
build.force
Refactor
StubPresentersUsecase3.dll
TempPE
Properties
MVPChainingFactory.Web
bin
Debug
Release
obj
Debug
Refactor
TempPE
Release
TempPE
Properties
MVPChainingFactory
bin
Release
Caching
ClassDiagram.cd
Factory
MVPChainingFactory.csproj.user
Presenters
Properties
View
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using NUnit.Framework;
using MVPChainingFactory.Factory;
using MVPChainingFactory.Caching;
using MVPChainingFactory.Presenters;
using MVPChainingFactory.View;
using Rhino.Mocks;
using Rhino.Mocks.Interfaces;
using Rhino.Mocks.Constraints;

namespace MVPChainingFactory.Tests
{
    [TestFixture]
    [Category("Factory API")]
    public class PresenterFactoryFixture
    {
        MockRepository _rep;
        ICacheItemManager<Dictionary<Type, ConstructorInfo>> _mockMetadataCacheManager;
        ICacheItemManager<PresenterSkeletonChain> _mockPresenterChainCacheManager;
        IEventRaiser _cmEvt;
        IEventRaiser _pccmEvt;
        const string _assemblyName = "MVPChainingFactory.Tests";

        // Intercept calls to the mock PresenterChainCacheManager to validate return values
        delegate void PutSimulator(PresenterSkeletonChain head);

        [SetUp]
        public void Setup()
        {
            _rep = new MockRepository();
            _mockMetadataCacheManager =
                _rep.CreateMock<ICacheItemManager<Dictionary<Type, ConstructorInfo>>>();
            _mockPresenterChainCacheManager =
                _rep.CreateMock<ICacheItemManager<PresenterSkeletonChain>>();
            
            // Setup initial expectations for the call to InitializeFactory() in [Setup]
            // Note - Every [Test] must make a call to InitializeFactory (which is required 
            // to construct the PresenterFactory anyway)
            _mockMetadataCacheManager.CacheDependencyAssembly = null;
            LastCall.Constraints(Is.Equal(_assemblyName));
            _mockMetadataCacheManager.CacheInvalidated += null;
            _cmEvt = LastCall.IgnoreArguments().GetEventRaiser();

            _mockPresenterChainCacheManager.CacheDependencyAssembly = null;
            LastCall.Constraints(Is.Equal(_assemblyName));
            _mockPresenterChainCacheManager.CacheInvalidated += null;
            _pccmEvt = LastCall.IgnoreArguments().GetEventRaiser();
            //  Donot put InitializeFactory call here as it would repeat the above expectations            
        }

        [Test]
        public void TestCacheItemManagerStateOnInitialize()
        {
            _rep.ReplayAll();
            using (_rep.Playback())
            {
                PresenterFactory.InitializeFactory(_mockMetadataCacheManager, _mockPresenterChainCacheManager, _assemblyName);                
            }
            Assert.IsNotNull(PresenterFactory.PresenterChainCacheManager);
            Assert.IsNotNull(PresenterFactory.PresenterMetadataCacheManager);
        }

        // todo: replace PresenterSkeleton with PresenterSkeletonChain to which I add current object "p"
        [Test]
        public void TestEventHookups()
        {
            PresenterSkeletonChain p = new PresenterSkeletonChain();
            Dictionary<Type, ConstructorInfo> d = new Dictionary<Type,ConstructorInfo>();
            using (_rep.Record())
            {
                Expect.Call(_mockPresenterChainCacheManager.Get()).Return(p);
                Expect.Call(_mockMetadataCacheManager.Get()).Return(d);                    
            }
            using (_rep.Playback())
            {
                PresenterFactory.InitializeFactory(_mockMetadataCacheManager, _mockPresenterChainCacheManager, _assemblyName);
                _pccmEvt.Raise(PresenterFactory.CACHE_KEY_PRESENTER_CHAIN, p);
                _cmEvt.Raise(PresenterFactory.CACHE_KEY_PRESENTER_METADATA, d);
            }
        }


        [Test]
        public void TestBuildPresenterChain()
        {
            PresenterSkeletonChain stubChain = CreateSkeletonChainStub();
            Dictionary<Type, ConstructorInfo> stubCtorInfo = CreateMetadataStub();

            Type[] expectedPresenterTypes = { 
                typeof(P14), typeof(P13), typeof(P12)
            };

            Expect.Call(_mockPresenterChainCacheManager.Get()).Return(stubChain);
            Expect.Call(_mockMetadataCacheManager.Get()).Return(stubCtorInfo);

            _rep.ReplayAll();

            Presenter head = null;
            using (_rep.Playback())
            {
                PresenterFactory.InitializeFactory(_mockMetadataCacheManager, _mockPresenterChainCacheManager, _assemblyName);
                head = PresenterFactory.BuildPresenterChain(null, PresenterChainMode.Break);
            }
            Assert.IsNotNull(head);
            Assert.AreEqual(PresenterChainMode.Break, head.ChainMode, "Unexpected Chain Mode");
            int i = 0;
            string mesg = "Expected presenter type at position {0} is {1}, actual is {2}";
            while (head != null) {
                Assert.AreEqual(expectedPresenterTypes[i], head.GetType(),
                    String.Format(mesg, (i+1), expectedPresenterTypes[i],head.GetType()));
                head = head.Next;
                i++;
            }
        }

        /// <summary>
        /// P14[H] -> P13 -> P12[T]
        /// P14 cant handle request
        /// P13 and P12 can handle request
        /// In chain mode A, P13 handles the request and the chain returns control back to the caller
        /// In chain mode B, both P13 and P12 handle the request as each node in the chain is given a
        /// chance to handle the request even if an earlier node already handled the request
        /// </summary>
        [Test]
        public void TestPresenterChainHandleRequest()
        {
            PresenterSkeletonChain stubChain = CreateSkeletonChainStub();
            Dictionary<Type, ConstructorInfo> stubCtorInfo = CreateMetadataStub();

            Expect.Call(_mockPresenterChainCacheManager.Get()).Return(stubChain).Repeat.Twice();
            Expect.Call(_mockMetadataCacheManager.Get()).Return(stubCtorInfo).Repeat.Twice();

            _rep.ReplayAll();

            Presenter head1 = null, head2 = null;
            using (_rep.Playback())
            {
                PresenterFactory.InitializeFactory(_mockMetadataCacheManager, _mockPresenterChainCacheManager,
                    _assemblyName);
                head1 = PresenterFactory.BuildPresenterChain(null, PresenterChainMode.Break);
                head2 = PresenterFactory.BuildPresenterChain(null, PresenterChainMode.Continue);
            }
            Assert.IsNotNull(head1); 
            head1.HandleRequest();
            List<Presenter> l1 = ToList(head1);
            Assert.IsNotNull(head2);
            head2.HandleRequest();
            List<Presenter> l2 = ToList(head2);
            // Mode A test
            Assert.AreEqual(false, l1[0].HasProcessedRequest, "Head should not have handled the request");
            Assert.AreEqual(true, l1[1].HasProcessedRequest, "Middle node should have handled the request");
            Assert.AreEqual(false, l1[2].HasProcessedRequest, "In mode A only the 1st node that can handle the request processes the request. Tail should not have got the chance to handle the request");

            // Mode B test
            for (int i = 1; i < 3; i++) Assert.AreEqual(true, l2[i].HasProcessedRequest, 
                String.Format("Failed for node {0}. In mode B, the middle and Tail nodes should have handled the request", (i+1)));
            Assert.AreEqual(false, l2[0].HasProcessedRequest, "Head node should not have handled the request");
        }

        [Test]
        public void TestSkeletonAccessorWhenNoItemInCache()
        {
            PresenterSkeletonChain dummyChain = new PresenterSkeletonChain();
            dummyChain.AddLast(new LinkedListNode<PresenterSkeleton>(
                new PresenterSkeleton(typeof(object))));
            PresenterSkeletonChain actualHead = null;
            using (_rep.Record())
            {
                // Return null to simulate item not cached scenario
                Expect.Call(_mockPresenterChainCacheManager.Get()).Return(null).Repeat.Twice();
                _mockPresenterChainCacheManager.Put(null);
                LastCall.Constraints(Is.NotNull()).Do((PutSimulator)
                        delegate(PresenterSkeletonChain head)
                        {
                            actualHead = head;
                            return;
                        }
                    ); 
                _mockMetadataCacheManager.Put(null);
                LastCall.Constraints(Is.NotNull());
                // The 3rd call to cachemanager Get() is executed after ScanPresenters invocation. 
                // So return a non null value
                Expect.Call(_mockPresenterChainCacheManager.Get()).Return(dummyChain);                
            }
            PresenterSkeletonChain ret = null;
            using (_rep.Playback())
            {
                PresenterFactory.InitializeFactory(_mockMetadataCacheManager, _mockPresenterChainCacheManager, _assemblyName);
                ret = PresenterFactory.PresenterSkeletonChain;                
            }
            Assert.IsNotNull(ret);            
        }

        //  Utility methods
        #region UTILITY methods
        private static Dictionary<Type, ConstructorInfo> CreateMetadataStub()
        {
            Dictionary<Type, ConstructorInfo> stubCtorInfo =
                new Dictionary<Type, ConstructorInfo>();
            stubCtorInfo.Add(typeof(P14), typeof(P14).GetConstructor(
                new Type[] { typeof(IView), typeof(PresenterChainMode) }));
            stubCtorInfo.Add(typeof(P13), typeof(P13).GetConstructor(
                new Type[] { typeof(IView), typeof(PresenterChainMode) }));
            stubCtorInfo.Add(typeof(P12), typeof(P12).GetConstructor(
                new Type[] { typeof(IView), typeof(PresenterChainMode) }));
            return stubCtorInfo;
        }

        private static PresenterSkeletonChain CreateSkeletonChainStub()
        {
            PresenterSkeletonChain stubChain = new PresenterSkeletonChain();

            stubChain.AddLast(new LinkedListNode<PresenterSkeleton>(
                new PresenterSkeleton(typeof(P14), Position.Head)));
            stubChain.AddLast(new LinkedListNode<PresenterSkeleton>(
                new PresenterSkeleton(typeof(P13))));
            stubChain.AddLast(new LinkedListNode<PresenterSkeleton>(
                new PresenterSkeleton(typeof(P12))));
            return stubChain;
        }

        List<Presenter> ToList(Presenter head)
        {
            List<Presenter> l = new List<Presenter>();
            while (head != null) { l.Add(head); head = head.Next; }
            return l;
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Rohit Gadagkar
Web Developer
United States United States
I am a tech lead working for Cap Gemini. Although I primarily work with the Microsoft technology stack (including .NET and legacy technologies) I like to keep myself informed about developments in the Java world.

You may also be interested in...

Pro
Pro
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160927.1 | Last Updated 14 Oct 2007
Article Copyright 2007 by Rohit Gadagkar
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid