diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index 93185a32d7..f4562c60fb 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -180,7 +180,7 @@ namespace Umbraco.Core.ObjectResolution l.UpgradeToWriteLock(); CurrentHttpContext.Items[_httpContextKey] = CreateInstances().ToArray(); } - return (List)CurrentHttpContext.Items[_httpContextKey]; + return (TResolved[])CurrentHttpContext.Items[_httpContextKey]; } case ObjectLifetimeScope.Application: @@ -254,6 +254,7 @@ namespace Umbraco.Core.ObjectResolution /// the resolver does not support removing types, or /// the type is not a valid type for the resolver. public void RemoveType() + where T : TResolved { RemoveType(typeof(T)); } @@ -319,6 +320,7 @@ namespace Umbraco.Core.ObjectResolution /// the resolver does not support adding types, or /// the type is not a valid type for the resolver, or the type is already in the collection of types. public void AddType() + where T : TResolved { AddType(typeof(T)); } @@ -372,6 +374,7 @@ namespace Umbraco.Core.ObjectResolution /// The zero-based index at which the type should be inserted. /// is out of range. public void InsertType(int index) + where T : TResolved { InsertType(index, typeof(T)); } @@ -419,6 +422,8 @@ namespace Umbraco.Core.ObjectResolution /// one of the types is not a valid type for the resolver, or the existing type is not in the collection, /// or the new type is already in the collection of types. public void InsertTypeBefore() + where Texisting : TResolved + where T : TResolved { InsertTypeBefore(typeof(Texisting), typeof(T)); } @@ -442,6 +447,7 @@ namespace Umbraco.Core.ObjectResolution /// The type to look for. /// A value indicating whether the type is already in the collection of types. public bool ContainsType() + where T : TResolved { return ContainsType(typeof(T)); } diff --git a/src/Umbraco.Core/ObjectResolution/Resolution.cs b/src/Umbraco.Core/ObjectResolution/Resolution.cs index 3254da30c5..6933ea6d6a 100644 --- a/src/Umbraco.Core/ObjectResolution/Resolution.cs +++ b/src/Umbraco.Core/ObjectResolution/Resolution.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.ObjectResolution public static void EnsureIsFrozen() { if (!IsFrozen) - throw new Exception("Resolution is not frozen, it is not yet possible to get values from it."); + throw new InvalidOperationException("Resolution is not frozen, it is not yet possible to get values from it."); } /// @@ -62,14 +62,15 @@ namespace Umbraco.Core.ObjectResolution if (Frozen != null) Frozen(null, null); } - - /// - /// Unfreezes resolution. - /// - /// To be used in unit tests. - internal static void Unfreeze() - { - IsFrozen = false; - } + + /// + /// Resets resolution, ie unfreezes it and clears Frozen event. + /// + /// To be used in unit tests. + internal static void Reset() + { + IsFrozen = false; + Frozen = null; + } } } diff --git a/src/Umbraco.Core/ObjectResolution/ResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ResolverBase.cs index 8c07aa306e..93fb6c4c0c 100644 --- a/src/Umbraco.Core/ObjectResolution/ResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ResolverBase.cs @@ -44,6 +44,7 @@ namespace Umbraco.Core.ObjectResolution set { + using (Resolution.Configuration) using (new WriteLock(ResolversLock)) { if (value == null) @@ -57,12 +58,28 @@ namespace Umbraco.Core.ObjectResolution } } + /// + /// Gets a value indicating whether a the singleton nstance has been set. + /// + /// To be used in unit tests. + internal static bool HasCurrent + { + get + { + using (new ReadLock(ResolversLock)) + { + return _resolver != null; + } + } + } + /// /// Resets the resolver singleton instance to null. /// /// To be used in unit tests. internal static void Reset() { + using (Resolution.Configuration) using (new WriteLock(ResolversLock)) { _resolver = null; diff --git a/src/Umbraco.Tests/CacheRefresherFactoryTests.cs b/src/Umbraco.Tests/CacheRefresherFactoryTests.cs index 726bb1c9bc..4583c90270 100644 --- a/src/Umbraco.Tests/CacheRefresherFactoryTests.cs +++ b/src/Umbraco.Tests/CacheRefresherFactoryTests.cs @@ -35,7 +35,7 @@ namespace Umbraco.Tests public void TearDown() { CacheRefreshersResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); } [Test] diff --git a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs index d371f7e709..a6547be834 100644 --- a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs +++ b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs @@ -233,7 +233,7 @@ namespace Umbraco.Tests.CodeFirst //reset the app context DataTypesResolver.Reset(); ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); PluginManager.Current = null; string path = TestHelper.CurrentAssemblyDirectory; diff --git a/src/Umbraco.Tests/DataTypeFactoryTests.cs b/src/Umbraco.Tests/DataTypeFactoryTests.cs index 734b0260c7..1026ce6a80 100644 --- a/src/Umbraco.Tests/DataTypeFactoryTests.cs +++ b/src/Umbraco.Tests/DataTypeFactoryTests.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests public void TearDown() { DataTypesResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); } [Test] diff --git a/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs b/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs index 5ef819b962..b8ae95974e 100644 --- a/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs +++ b/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Migrations public void TearDown() { MigrationResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Migrations/TargetVersionSixthMigrationsTest.cs b/src/Umbraco.Tests/Migrations/TargetVersionSixthMigrationsTest.cs index c56dbf55eb..20bb537c51 100644 --- a/src/Umbraco.Tests/Migrations/TargetVersionSixthMigrationsTest.cs +++ b/src/Umbraco.Tests/Migrations/TargetVersionSixthMigrationsTest.cs @@ -70,7 +70,7 @@ namespace Umbraco.Tests.Migrations public void TearDown() { MigrationResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs b/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs index 871ecf3c29..e348b2dcf1 100644 --- a/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs +++ b/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs @@ -95,7 +95,7 @@ namespace Umbraco.Tests.Migrations.Upgrades PluginManager.Current = null; SyntaxConfig.SqlSyntaxProvider = null; MigrationResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); TestHelper.CleanContentDirectories(); diff --git a/src/Umbraco.Tests/Persistence/MySqlTableByTableTest.cs b/src/Umbraco.Tests/Persistence/MySqlTableByTableTest.cs index 80388d5c63..98b12940b6 100644 --- a/src/Umbraco.Tests/Persistence/MySqlTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/MySqlTableByTableTest.cs @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Persistence //reset the app context ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); } diff --git a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs index eab36ac329..9f3b094ace 100644 --- a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs @@ -68,7 +68,7 @@ namespace Umbraco.Tests.Persistence //reset the app context ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); } diff --git a/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs index 4c18b04b59..0bd5bcf291 100644 --- a/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Persistence //reset the app context ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); } diff --git a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs index 074265e78e..91a1a50e00 100644 --- a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs +++ b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Publishing //reset the app context DataTypesResolver.Reset(); ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); diff --git a/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs b/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs index 411abc3d20..2e3a3a05eb 100644 --- a/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs @@ -8,45 +8,65 @@ using umbraco.interfaces; namespace Umbraco.Tests.Resolvers { - [TestFixture] public class ActionsResolverTests { [SetUp] public void Initialize() { - TestHelper.SetupLog4NetForTests(); + TestHelper.SetupLog4NetForTests(); - //this ensures its reset + Resolution.Reset(); + ActionsResolver.Reset(); + + // this ensures it's reset PluginManager.Current = new PluginManager(false); - //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver PluginManager.Current.AssembliesToScan = new[] { - this.GetType().Assembly + this.GetType().Assembly // this assembly only }; - - ActionsResolver.Current = new ActionsResolver( - () => PluginManager.Current.ResolveActions()); - - Resolution.Freeze(); } [TearDown] public void TearDown() { - ActionsResolver.Reset(); - Resolution.Unfreeze(); - } + Resolution.Reset(); + ActionsResolver.Reset(); + PluginManager.Current.AssembliesToScan = null; + } - [Test] - public void Create_Types() + // NOTE + // ManyResolverTests ensure that we'll get our actions back and ActionsResolver works, + // so all we're testing here is that plugin manager _does_ find our actions + // which should be ensured by PlugingManagerTests anyway, so this is useless? + // maybe not as it seems to handle the "instance" thing... so we test that we respect the singleton? + [Test] + public void FindAllActions() { - var found = ActionsResolver.Current.Actions; - Assert.AreEqual(2, found.Count()); - } + ActionsResolver.Current = new ActionsResolver( + () => PluginManager.Current.ResolveActions()); + + Resolution.Freeze(); + + var actions = ActionsResolver.Current.Actions; + Assert.AreEqual(2, actions.Count()); + + // order is unspecified, but both must be there + bool hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction; + bool hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction; + Assert.IsTrue(hasAction1); + Assert.IsTrue(hasAction2); + + SingletonAction action = (SingletonAction)(actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1)); + + // ensure we respect the singleton + Assert.AreSame(SingletonAction.Instance, action); + } #region Classes for tests + public class SingletonAction : IAction { //create singleton @@ -176,7 +196,6 @@ namespace Umbraco.Tests.Resolvers } #endregion } - #endregion } diff --git a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs index 426df9109f..d7040057f6 100644 --- a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Resolvers [TearDown] public void TearDown() { - Resolution.Unfreeze(); + Resolution.Reset(); } [Test] diff --git a/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs b/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs index ad5992f122..6def8c0fc1 100644 --- a/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs @@ -16,39 +16,54 @@ namespace Umbraco.Tests.Resolvers [SetUp] public void Initialize() { - TestHelper.SetupLog4NetForTests(); + TestHelper.SetupLog4NetForTests(); - //this ensures its reset + Resolution.Reset(); + MacroFieldEditorsResolver.Reset(); + + + // this ensures it's reset PluginManager.Current = new PluginManager(false); - //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver PluginManager.Current.AssembliesToScan = new[] { this.GetType().Assembly }; - - MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver( - () => PluginManager.Current.ResolveMacroRenderings()); - - Resolution.Freeze(); } [TearDown] public void TearDown() { - MacroFieldEditorsResolver.Reset(); - Resolution.Unfreeze(); + Resolution.Reset(); + MacroFieldEditorsResolver.Reset(); PluginManager.Current.AssembliesToScan = null; } - [Test] - public void Find_Types() + // NOTE + // ManyResolverTests ensure that we'll get our actions back and MacroFieldEditorsResolver works, + // so all we're testing here is that plugin manager _does_ find our macro control types + // which should be ensured by PlugingManagerTests anyway, so this is useless? + [Test] + public void FindAllTypes() { - var found = MacroFieldEditorsResolver.Current.MacroControlTypes; - Assert.AreEqual(2, found.Count()); - } + MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver( + () => PluginManager.Current.ResolveMacroRenderings()); + + Resolution.Freeze(); + + var types = MacroFieldEditorsResolver.Current.MacroControlTypes; + Assert.AreEqual(2, types.Count()); + + // order is unspecified, but both must be there + bool hasType1 = types.ElementAt(0) == typeof(ControlMacroRendering) || types.ElementAt(1) == typeof(ControlMacroRendering); + bool hasType2 = types.ElementAt(0) == typeof(NonControlMacroRendering) || types.ElementAt(1) == typeof(NonControlMacroRendering); + Assert.IsTrue(hasType1); + Assert.IsTrue(hasType2); + } #region Classes for tests + public class ControlMacroRendering : Control, IMacroGuiRendering { public string Value @@ -76,6 +91,7 @@ namespace Umbraco.Tests.Resolvers get { throw new NotImplementedException(); } } } - #endregion + + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs deleted file mode 100644 index 75a73f79ee..0000000000 --- a/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Web; -using NUnit.Framework; -using Umbraco.Core.ObjectResolution; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Resolvers -{ - [TestFixture] - public class ManyObjectResolverTests - { - - [SetUp] - public void Initialize() - { - - } - - [TearDown] - public void TearDown() - { - Resolution.Unfreeze(); - } - - [Test] - public void Ensure_Transient_Object_Creation() - { - var resolver = new TransientObjectsResolver(); - resolver.AddType(); - - Resolution.Freeze(); - - 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(); - - Resolution.Freeze(); - - 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(); - - Resolution.Freeze(); - - 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 Test classes - - private interface ITestInterface - { - } - - private class TransientObject : ITestInterface - { - } - - private sealed class TransientObjectsResolver : ManyObjectsResolverBase - { - public TransientObjectsResolver() - : base(ObjectLifetimeScope.Transient) - { - - } - public IEnumerable Objects - { - get { return Values; } - } - } - - private sealed class ApplicationObjectsResolver : ManyObjectsResolverBase - { - public ApplicationObjectsResolver() - : base(ObjectLifetimeScope.Application) - { - - } - public IEnumerable Objects - { - get { return Values; } - } - } - - private sealed class HttpRequestObjectsResolver : ManyObjectsResolverBase - { - public HttpRequestObjectsResolver(HttpContextBase httpContext) - : base(httpContext) - { - - } - public IEnumerable Objects - { - get { return Values; } - } - } - - #endregion - - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs b/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs new file mode 100644 index 0000000000..463148bd05 --- /dev/null +++ b/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs @@ -0,0 +1,381 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; + +using Umbraco.Core; +using Umbraco.Core.ObjectResolution; +using Umbraco.Tests.TestHelpers; + +using NUnit.Framework; + +namespace Umbraco.Tests.Resolvers +{ + [TestFixture] + public class ManyResolverTests + { + [SetUp] + public void Setup() + { + TestHelper.SetupLog4NetForTests(); + + Resolution.Reset(); + ManyResolver.Reset(); + } + + [TearDown] + public void TearDown() + { + Resolution.Reset(); + ManyResolver.Reset(); + } + + #region Resolvers and Resolved + + public abstract class Resolved + { } + + public class Resolved1 : Resolved + { } + + [WeightedPlugin(5)] // default is 10 + public class Resolved2 : Resolved + { } + + public class Resolved3 : Resolved + { } + + public class Resolved4 // not! : Resolved + { } + + public class ManyResolver : ManyObjectsResolverBase + { + public ManyResolver() + : base() + { } + + public ManyResolver(IEnumerable value) + : base(value) + { } + + public ManyResolver(IEnumerable value, ObjectLifetimeScope scope) + : base(value, scope) + { } + + public ManyResolver(HttpContextBase httpContext) + : base(httpContext) + { } + + public IEnumerable SortedResolvedObjects { get { return GetSortedValues(); } } + public IEnumerable ResolvedObjects { get { return Values; } } + } + + #endregion + + #region Test ManyResolver types collection manipulation + + [Test] + public void ManyResolverContainsTypes() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + Assert.IsFalse(resolver.ContainsType()); + //Assert.IsFalse(resolver.ContainsType()); // does not compile + } + + [Test] + public void ManyResolverCanAddTypeBeforeFreeze() + { + var resolver = new ManyResolver(); + resolver.AddType(); + resolver.AddType(); + + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + Assert.IsFalse(resolver.ContainsType()); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotAddTypeOnceFrozen() + { + var resolver = new ManyResolver(); + Resolution.Freeze(); + resolver.AddType(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotAddTypeAgain() + { + var resolver = new ManyResolver(); + resolver.AddType(); + resolver.AddType(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotAddInvalidType() + { + var resolver = new ManyResolver(); + //resolver.AddType(); // does not compile + resolver.AddType(typeof(Resolved4)); // throws + } + + [Test] + public void ManyResolverCanRemoveTypeBeforeFreeze() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.RemoveType(); + + Assert.IsTrue(resolver.ContainsType()); + Assert.IsFalse(resolver.ContainsType()); + Assert.IsFalse(resolver.ContainsType()); + } + + [Test] + public void ManyResolverCanRemoveAbsentType() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.RemoveType(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotRemoveInvalidType() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + //resolver.RemoveType(); // does not compile + resolver.RemoveType(typeof(Resolved4)); // throws + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotRemoveTypeOnceFrozen() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + resolver.RemoveType(); // throws + } + + [Test] + public void ManyResolverCanInsertTypeBeforeFreeze() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.InsertType(0); + + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertTypeOnceFrozen() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + resolver.InsertType(0); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertTypeAgain() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.InsertType(0); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertInvalidType() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + //resolver.InsertType(0); // does not compile + resolver.InsertType(0, typeof(Resolved4)); // throws + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void ManyResolverCannotInsertTypeAtWrongIndex() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.InsertType(99, typeof(Resolved3)); // throws + } + + // + + [Test] + public void ManyResolverCanInsertBeforeTypeBeforeFreeze() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.InsertTypeBefore(); + + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + Assert.IsTrue(resolver.ContainsType()); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertBeforeTypeOnceFrozen() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + resolver.InsertTypeBefore(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertBeforeTypeAgain() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.InsertTypeBefore(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertBeforeAbsentType() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1) }); + resolver.InsertTypeBefore(); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotInsertBeforeInvalidType() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + //resolver.InsertTypeBefore(); // does not compile + resolver.InsertTypeBefore(typeof(Resolved2), typeof(Resolved4)); // throws + } + + #endregion + + #region Test ManyResolver resolution + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ManyResolverCannotGetValuesBeforeFreeze() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + var values = resolver.ResolvedObjects; + } + + [Test] + public void ManyResolverCannotGetValuesBeforeFreezeUnless() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + resolver.CanResolveBeforeFrozen = true; + var values = resolver.ResolvedObjects; + } + + [Test] + public void ManyResolverCanGetValuesOnceFrozen() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + var values = resolver.ResolvedObjects; + + Assert.AreEqual(2, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + } + + [Test] + public void ManyResolverDefaultLifetimeScopeIsApplication() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + var values = resolver.ResolvedObjects; + + Assert.AreEqual(2, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + + var values2 = resolver.ResolvedObjects; + Assert.AreEqual(2, values2.Count()); + Assert.AreSame(values.ElementAt(0), values2.ElementAt(0)); + Assert.AreSame(values.ElementAt(1), values2.ElementAt(1)); + } + + [Test] + public void ManyResolverTransientLifetimeScope() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }, ObjectLifetimeScope.Transient); + Resolution.Freeze(); + var values = resolver.ResolvedObjects; + + Assert.AreEqual(2, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + + var values2 = resolver.ResolvedObjects; + Assert.AreEqual(2, values2.Count()); + Assert.AreNotSame(values.ElementAt(0), values2.ElementAt(0)); + Assert.AreNotSame(values.ElementAt(1), values2.ElementAt(1)); + } + + [Test] + public void ManyResolverDefaultOrderOfTypes() + { + var resolver = new ManyResolver(); + resolver.AddType(); + resolver.InsertType(0); + resolver.InsertTypeBefore(); + Resolution.Freeze(); + var values = resolver.ResolvedObjects; + + Assert.AreEqual(3, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + Assert.IsInstanceOf(values.ElementAt(2)); + } + + [Test] + public void ManyResolverHttpRequestLifetimeScope() + { + var httpContextFactory = new FakeHttpContextFactory("~/Home"); + var httpContext = httpContextFactory.HttpContext; + var resolver = new ManyResolver(httpContext); + + resolver.AddType(); + resolver.AddType(); + Resolution.Freeze(); + + var values = resolver.ResolvedObjects; + Assert.AreEqual(2, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + + var values2 = resolver.ResolvedObjects; + Assert.AreEqual(2, values2.Count()); + Assert.AreSame(values.ElementAt(0), values2.ElementAt(0)); + Assert.AreSame(values.ElementAt(1), values2.ElementAt(1)); + + httpContextFactory.HttpContext.Items.Clear(); // new context + + var values3 = resolver.ResolvedObjects; + Assert.AreEqual(2, values3.Count()); + Assert.AreNotSame(values.ElementAt(0), values3.ElementAt(0)); + Assert.AreNotSame(values.ElementAt(1), values3.ElementAt(1)); + } + + [Test] + public void ManyResolverWeightedResolution() + { + var resolver = new ManyResolver(new Type[] { typeof(Resolved1), typeof(Resolved2) }); + Resolution.Freeze(); + + var values = resolver.SortedResolvedObjects; + Assert.AreEqual(2, values.Count()); + Assert.IsInstanceOf(values.ElementAt(0)); + Assert.IsInstanceOf(values.ElementAt(1)); + } + + #endregion + } +} diff --git a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs index 08077a29e3..fd3c6937fd 100644 --- a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs @@ -17,39 +17,51 @@ namespace Umbraco.Tests.Resolvers { TestHelper.SetupLog4NetForTests(); - //this ensures its reset + Resolution.Reset(); + PackageActionsResolver.Reset(); + + // ensures it's reset PluginManager.Current = new PluginManager(false); - //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver PluginManager.Current.AssembliesToScan = new[] { - this.GetType().Assembly + this.GetType().Assembly // this assembly only }; - - PackageActionsResolver.Current = new PackageActionsResolver( - () => PluginManager.Current.ResolvePackageActions()); - - Resolution.Freeze(); } [TearDown] public void TearDown() { - PackageActionsResolver.Reset(); - Resolution.Unfreeze(); - } - - /// - /// Ensures all IPackageActions are found - /// - [Test] - public void Find_Package_Actions() + Resolution.Reset(); + PackageActionsResolver.Reset(); + PluginManager.Current.AssembliesToScan = null; + } + + // NOTE + // ManyResolverTests ensure that we'll get our actions back and PackageActionResolver works, + // so all we're testing here is that plugin manager _does_ find our package actions + // which should be ensured by PlugingManagerTests anyway, so this is useless? + [Test] + public void FindAllPackageActions() { + PackageActionsResolver.Current = new PackageActionsResolver( + () => PluginManager.Current.ResolvePackageActions()); + + Resolution.Freeze(); + var actions = PackageActionsResolver.Current.PackageActions; Assert.AreEqual(2, actions.Count()); - } + + // order is unspecified, but both must be there + bool hasAction1 = actions.ElementAt(0) is PackageAction1 || actions.ElementAt(1) is PackageAction1; + bool hasAction2 = actions.ElementAt(0) is PackageAction2 || actions.ElementAt(1) is PackageAction2; + Assert.IsTrue(hasAction1); + Assert.IsTrue(hasAction2); + } #region Classes for tests + public class PackageAction1 : IPackageAction { public bool Execute(string packageName, XmlNode xmlData) @@ -95,6 +107,7 @@ namespace Umbraco.Tests.Resolvers throw new NotImplementedException(); } } - #endregion + + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Resolvers/ResolutionTests.cs b/src/Umbraco.Tests/Resolvers/ResolutionTests.cs new file mode 100644 index 0000000000..bb517adff1 --- /dev/null +++ b/src/Umbraco.Tests/Resolvers/ResolutionTests.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Umbraco.Core; +using Umbraco.Core.ObjectResolution; +using Umbraco.Tests.TestHelpers; + +using NUnit.Framework; + +namespace Umbraco.Tests.Resolvers +{ + [TestFixture] + public class ResolutionTests + { + [SetUp] + public void Setup() + { + TestHelper.SetupLog4NetForTests(); + + Resolution.Reset(); + BaseResolver.Reset(); + } + + [TearDown] + public void TearDown() + { + Resolution.Reset(); + BaseResolver.Reset(); + } + + #region Resolvers and Resolved + + class BaseResolver : ResolverBase + { } + + #endregion + + #region Test Resolution + + [Test] + public void ResolutionCanFreeze() + { + Resolution.Freeze(); + Assert.IsTrue(Resolution.IsFrozen); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ResolutionCannotFreezeAgain() + { + Resolution.Freeze(); + Resolution.Freeze(); // throws + } + + [Test] + public void ResolutionCanReset() + { + Resolution.Freeze(); + Resolution.Reset(); + Assert.IsFalse(Resolution.IsFrozen); + } + + [Test] + public void ResolutionCanConfigureBeforeFreeze() + { + using (Resolution.Configuration) + { } + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ResolutionCannotConfigureOnceFrozen() + { + Resolution.Freeze(); + + using (Resolution.Configuration) // throws + { } + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ResolutionCanDetectIfNotFrozen() + { + Resolution.EnsureIsFrozen(); // throws + } + + [Test] + public void ResolutionCanEnsureIsFrozen() + { + Resolution.Freeze(); + Resolution.EnsureIsFrozen(); + } + + [Test] + public void ResolutionFrozenEventTriggers() + { + int count = 0; + object copySender = null; + EventArgs copyArgs = null; + Resolution.Frozen += (sender, args) => + { + copySender = sender; + copyArgs = args; + count++; + }; + Assert.AreEqual(0, count); + Resolution.Freeze(); + + Assert.AreEqual(1, count); + Assert.IsNull(copySender); + Assert.IsNull(copyArgs); + } + + [Test] + public void ResolutionResetClearsFrozenEvent() + { + int count = 0; + Resolution.Frozen += (sender, args) => + { + count++; + }; + Resolution.Freeze(); + Assert.AreEqual(1, count); + + Resolution.Reset(); + + Resolution.Freeze(); + Assert.AreEqual(1, count); + } + + #endregion + + #region Test ResolverBase + + // unused + + [Test] + public void BaseResolverCurrentCanBeNullOnFreeze() + { + // does not throw, even though BaseResolver.Current is not initialized + Resolution.Freeze(); + } + + // set + + [Test] + public void BaseResolverCurrentCanSetBeforeFreeze() + { + BaseResolver.Current = new BaseResolver(); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void BaseResolverCurrentCannotSetToNull() + { + BaseResolver.Current = null; // throws + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void BaseResolverCurrentCannotSetAgain() + { + BaseResolver.Current = new BaseResolver(); + + // cannot set again + BaseResolver.Current = new BaseResolver(); // throws + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void BaseResolverCurrentCannotSetOnceFrozen() + { + Resolution.Freeze(); + + // cannot set once frozen + BaseResolver.Current = new BaseResolver(); // throws + } + + // get + + // ignore: see BaseResolverCurrentCanGetBeforeFreeze + //[Test] + [ExpectedException(typeof(InvalidOperationException))] + public void BaseResolverCurrentCannotGetBeforeFreeze() + { + BaseResolver.Current = new BaseResolver(); + + // cannot get before freeze + var resolver = BaseResolver.Current; // throws + } + + [Test] + public void BaseResolverCurrentCanGetBeforeFreeze() + { + BaseResolver.Current = new BaseResolver(); + var resolver = BaseResolver.Current; + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void BaseResolverCurrentCannotGetIfNotSet() + { + Resolution.Freeze(); + + // cannot get before freeze + var resolver = BaseResolver.Current; // throws + } + + [Test] + public void BaseResolverCurrentCanGetOnceFrozen() + { + BaseResolver.Current = new BaseResolver(); + Resolution.Freeze(); + var resolver = BaseResolver.Current; + } + + #endregion + } +} diff --git a/src/Umbraco.Tests/Resolvers/SingleResolverTests.cs b/src/Umbraco.Tests/Resolvers/SingleResolverTests.cs new file mode 100644 index 0000000000..8513324cfe --- /dev/null +++ b/src/Umbraco.Tests/Resolvers/SingleResolverTests.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Umbraco.Core; +using Umbraco.Core.ObjectResolution; +using Umbraco.Tests.TestHelpers; + +using NUnit.Framework; + +namespace Umbraco.Tests.Resolvers +{ + [TestFixture] + public class SingleResolverTests + { + [SetUp] + public void Setup() + { + TestHelper.SetupLog4NetForTests(); + + Resolution.Reset(); + SingleResolver.Reset(); + } + + [TearDown] + public void TearDown() + { + Resolution.Reset(); + SingleResolver.Reset(); + } + + #region Resolvers and Resolved + + public class Resolved + { } + + public class SingleResolver : SingleObjectResolverBase + { + public SingleResolver() + : base() + { } + + public SingleResolver(bool canBeNull) + : base(canBeNull) + { } + + public SingleResolver(Resolved value) + : base(value) + { } + + public SingleResolver(Resolved value, bool canBeNull) + : base(value, canBeNull) + { } + + public Resolved Resolved { get { return Value; } set { Value = value; } } + } + + #endregion + + #region Test SingleResolver + + [Test] + public void SingleResolverCanSetValueBeforeFreeze() + { + var resolver = new SingleResolver(); + resolver.Resolved = new Resolved(); + } + + [Test] // is this normal? + public void SingleResolverCanInitializeWithNullValueEvenIfCannotBeNull() + { + var resolver = new SingleResolver(null, false); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void SingleResolverCannotSetValueToNullIfCannotBeNull() + { + var resolver = new SingleResolver(); + resolver.Resolved = null; // throws + } + + [Test] + public void SingleResolverCanSetValueToNullIfCanBeNull() + { + var resolver = new SingleResolver(true); + resolver.Resolved = null; + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void SingleResolverCannotSetValueOnceFrozen() + { + var resolver = new SingleResolver(); + Resolution.Freeze(); + resolver.Resolved = new Resolved(); // throws + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void SingleResolverCannotGetValueBeforeFreeze() + { + var resolver = new SingleResolver(); + resolver.Resolved = new Resolved(); + var resolved = resolver.Resolved; // throws + } + + [Test] + public void SingleResolverCanGetValueOnceFrozen() + { + var resolver = new SingleResolver(); + var resolved = resolver.Resolved = new Resolved(); + Resolution.Freeze(); + Assert.AreSame(resolved, resolver.Resolved); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void SingleResolverCannotGetNullValueIfCannotBeNull() + { + var resolver = new SingleResolver(); + Resolution.Freeze(); + var resolved = resolver.Resolved; // throws + } + + [Test] + public void SingleResolverCanGetNullValueIfCanBeNull() + { + var resolver = new SingleResolver(true); + Resolution.Freeze(); + Assert.IsNull(resolver.Resolved); + } + + #endregion + } +} diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs index 9d22190b64..a7762236cf 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs @@ -90,7 +90,7 @@ namespace Umbraco.Tests.TestHelpers SqlCeContextGuardian.CloseBackgroundConnection(); ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); TestHelper.CleanContentDirectories(); diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseTest.cs index 05074391da..79b75f9696 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseTest.cs @@ -83,7 +83,7 @@ namespace Umbraco.Tests.TestHelpers //reset the app context ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); } diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 0b6983b3ca..b31d358662 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -103,7 +103,7 @@ namespace Umbraco.Tests.TestHelpers ApplicationContext.Current = null; - Resolution.Unfreeze(); + Resolution.Reset(); RepositoryResolver.Reset(); TestHelper.CleanContentDirectories(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 5acb8ab0e0..d3b7c20c06 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -246,6 +246,9 @@ + + + @@ -293,7 +296,6 @@ -