From c2ee1e63bb8403e1adcc90a7350878a5f57942dd Mon Sep 17 00:00:00 2001 From: "shannon@ShandemVaio" Date: Wed, 1 Aug 2012 10:48:19 +0600 Subject: [PATCH] Added unit tests for ManyObjectResolverBase for the different lifetime scope of instantiated objects. --- .../LegacyTransientObjectsResolver.cs | 4 +- .../Resolving/ManyObjectResolverBase.cs | 97 ++++++++-------- src/Umbraco.Tests/ContentStoreTests.cs | 105 ++++++++++++++++++ .../Routing/DocumentLookupsResolver.cs | 2 +- 4 files changed, 156 insertions(+), 52 deletions(-) diff --git a/src/Umbraco.Core/LegacyTransientObjectsResolver.cs b/src/Umbraco.Core/LegacyTransientObjectsResolver.cs index 35602632ad..a884070113 100644 --- a/src/Umbraco.Core/LegacyTransientObjectsResolver.cs +++ b/src/Umbraco.Core/LegacyTransientObjectsResolver.cs @@ -32,11 +32,11 @@ namespace Umbraco.Core /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. /// protected LegacyTransientObjectsResolver(IEnumerable refreshers) - : base(true) + : base(ObjectLifetimeScope.Transient) // false = new objects every time { foreach (var l in refreshers) { - this.Add(l); + this.AddType(l); } } #endregion diff --git a/src/Umbraco.Core/Resolving/ManyObjectResolverBase.cs b/src/Umbraco.Core/Resolving/ManyObjectResolverBase.cs index 52ac1a4ddd..33d9c234fa 100644 --- a/src/Umbraco.Core/Resolving/ManyObjectResolverBase.cs +++ b/src/Umbraco.Core/Resolving/ManyObjectResolverBase.cs @@ -8,7 +8,6 @@ namespace Umbraco.Core.Resolving internal abstract class ManyObjectResolverBase where TResolved : class { - private readonly bool _instancePerApplication = false; private List _applicationInstances = null; private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); @@ -16,45 +15,55 @@ namespace Umbraco.Core.Resolving /// /// Initializes a new instance of the class with an empty list of objects. /// - /// If set to true will resolve singleton objects which will be created once for the lifetime of the application - protected ManyObjectResolverBase(bool instancePerApplication = true) + /// The lifetime scope of instantiated objects, default is per Application + protected ManyObjectResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application) { - _instancePerApplication = instancePerApplication; + if (scope == ObjectLifetimeScope.HttpRequest) + { + if (HttpContext.Current == null) + { + throw new InvalidOperationException("Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null"); + } + CurrentHttpContext = new HttpContextWrapper(HttpContext.Current); + } + + LifetimeScope = scope; InstanceTypes = new List(); } + /// + /// Initializes a new instance of the class with an empty list of objects. + /// with creation of objects based on an HttpRequest lifetime scope. + /// + /// + protected ManyObjectResolverBase(HttpContextBase httpContext) + { + LifetimeScope = ObjectLifetimeScope.HttpRequest; + CurrentHttpContext = httpContext; + InstanceTypes = new List(); + } + + /// + /// Initializes a new instance of the class with an initial list of objects. + /// + /// The list of objects. + /// If set to true will resolve singleton objects which will be created once for the lifetime of the application + protected ManyObjectResolverBase(IEnumerable value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) + : this(scope) + { + InstanceTypes = new List(value); + } + /// /// Initializes a new instance of the class with an initial list of objects /// with creation of objects based on an HttpRequest lifetime scope. /// /// - protected ManyObjectResolverBase(HttpContextBase httpContext) - : this(false) - { - CurrentHttpContext = httpContext; - } - - /// - /// Initializes a new instance of the class with an initial list of objects. - /// - /// The list of objects. - /// If set to true will resolve singleton objects which will be created once for the lifetime of the application - protected ManyObjectResolverBase(IEnumerable value, bool instancePerApplication = true) - { - _instancePerApplication = instancePerApplication; - InstanceTypes = new List(value); - } - - /// - /// Initializes a new instance of the class with an empty list of objects - /// with creation of objects based on an HttpRequest lifetime scope. - /// - /// /// protected ManyObjectResolverBase(HttpContextBase httpContext, IEnumerable value) - : this(value, false) + : this(httpContext) { - CurrentHttpContext = httpContext; + InstanceTypes = new List(value); } #endregion @@ -72,17 +81,7 @@ namespace Umbraco.Core.Resolving /// /// Returns the ObjectLifetimeScope for created objects /// - protected ObjectLifetimeScope LifetimeScope - { - get - { - if (_instancePerApplication) - return ObjectLifetimeScope.Application; - if (CurrentHttpContext != null) - return ObjectLifetimeScope.HttpRequest; - return ObjectLifetimeScope.Transient; - } - } + protected ObjectLifetimeScope LifetimeScope { get; private set; } /// /// Returns the list of new object instances. @@ -106,7 +105,7 @@ namespace Umbraco.Core.Resolving CurrentHttpContext.Items[this.GetType().FullName] = new List( PluginTypeResolver.Current.CreateInstances(InstanceTypes)); } - return _applicationInstances; + return (List)CurrentHttpContext.Items[this.GetType().FullName]; } case ObjectLifetimeScope.Application: //create new instances per application, this means we'll lazily create them and once created, cache them @@ -132,7 +131,7 @@ namespace Umbraco.Core.Resolving /// Removes a type. /// /// The type to remove. - public void Remove(Type value) + public void RemoveType(Type value) { EnsureCorrectType(value); using (new WriteLock(_lock)) @@ -145,16 +144,16 @@ namespace Umbraco.Core.Resolving /// Removes a type. /// /// - public void Remove() + public void RemoveType() { - Remove(typeof (T)); + RemoveType(typeof (T)); } /// /// Adds a Type to the end of the list. /// /// The object to be added. - public void Add(Type value) + public void AddType(Type value) { EnsureCorrectType(value); using (var l = new UpgradeableReadLock(_lock)) @@ -173,9 +172,9 @@ namespace Umbraco.Core.Resolving /// Adds a Type to the end of the list. /// /// - public void Add() + public void AddType() { - Add(typeof (T)); + AddType(typeof (T)); } /// @@ -194,7 +193,7 @@ namespace Umbraco.Core.Resolving /// /// The zero-based index at which the object should be inserted. /// The object to insert. - public void Insert(int index, Type value) + public void InsertType(int index, Type value) { EnsureCorrectType(value); using (var l = new UpgradeableReadLock(_lock)) @@ -214,9 +213,9 @@ namespace Umbraco.Core.Resolving /// /// /// - public void Insert(int index) + public void InsertType(int index) { - Insert(index, typeof (T)); + InsertType(index, typeof (T)); } private void EnsureCorrectType(Type t) diff --git a/src/Umbraco.Tests/ContentStoreTests.cs b/src/Umbraco.Tests/ContentStoreTests.cs index f4fb3d4028..675143b1a5 100644 --- a/src/Umbraco.Tests/ContentStoreTests.cs +++ b/src/Umbraco.Tests/ContentStoreTests.cs @@ -1,6 +1,10 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web; using System.Xml; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Resolving; using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -8,6 +12,107 @@ using umbraco.BusinessLogic; namespace Umbraco.Tests { + [TestFixture] + public class ManyObjectResolverTests + { + + [Test] + public void Ensure_Transient_Object_Creation() + { + var resolver = new TransientObjectsResolver(); + resolver.AddType(); + + var instances1 = resolver.Objects; + var instances2 = resolver.Objects; + + Assert.IsFalse(object.ReferenceEquals(instances1.Single(), instances2.Single())); + } + + [Test] + public void Ensure_Application_Object_Creation() + { + var resolver = new ApplicationObjectsResolver(); + resolver.AddType(); + + var instances1 = resolver.Objects; + var instances2 = resolver.Objects; + + Assert.IsTrue(object.ReferenceEquals(instances1.Single(), instances2.Single())); + } + + [Test] + public void Ensure_HttpRequest_Object_Creation() + { + var httpContextFactory = new FakeHttpContextFactory("~/Home"); + + var resolver = new HttpRequestObjectsResolver(httpContextFactory.HttpContext); + resolver.AddType(); + + var instances1 = resolver.Objects; + var instances2 = resolver.Objects; + + Assert.IsTrue(object.ReferenceEquals(instances1.Single(), instances2.Single())); + + //now clear the items, this is like mimicing a new request + httpContextFactory.HttpContext.Items.Clear(); + + var instances3 = resolver.Objects; + Assert.IsFalse(object.ReferenceEquals(instances1.Single(), instances3.Single())); + } + + #region + + private interface ITestInterface + { + } + + private class TransientObject : ITestInterface + { + } + + private sealed class TransientObjectsResolver : ManyObjectResolverBase + { + public TransientObjectsResolver() + : base(ObjectLifetimeScope.Transient) + { + + } + public IEnumerable Objects + { + get { return Values; } + } + } + + private sealed class ApplicationObjectsResolver : ManyObjectResolverBase + { + public ApplicationObjectsResolver() + : base(ObjectLifetimeScope.Application) + { + + } + public IEnumerable Objects + { + get { return Values; } + } + } + + private sealed class HttpRequestObjectsResolver : ManyObjectResolverBase + { + public HttpRequestObjectsResolver(HttpContextBase httpContext) + : base(httpContext) + { + + } + public IEnumerable Objects + { + get { return Values; } + } + } + + #endregion + + } + [TestFixture] public class ContentStoreTests { diff --git a/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs b/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs index 85ecb11d79..5fe0cffdee 100644 --- a/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs +++ b/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.Routing { foreach (var l in lookups) { - this.Add(l); + this.AddType(l); } } #endregion