Commit 45cdce2

mo <mo@mokhan.ca>
2009-10-11 15:06:47
added singleton specs.
1 parent 5cc71a9
Changed files (6)
product
application.console
application.tests
product/application.console/application.console/infrastructure/Factory.cs
@@ -4,7 +4,7 @@ namespace gorilla.migrations.console.infrastructure
 {
     public class Factory : Scope
     {
-        public object apply_to(Func<object> factory)
+        public T apply_to<T>(Func<T> factory)
         {
             return factory();
         }
product/application.console/application.console/infrastructure/Scope.cs
@@ -4,6 +4,6 @@ namespace gorilla.migrations.console.infrastructure
 {
     public interface Scope
     {
-        object apply_to(Func<object> factory);
+        T apply_to<T>(Func<T> factory);
     }
 }
\ No newline at end of file
product/application.console/application.console/infrastructure/Singleton.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace gorilla.migrations.console.infrastructure
+{
+    public class Singleton : Scope
+    {
+        Func<object> cached_factory;
+
+        public T apply_to<T>(Func<T> factory)
+        {
+            if (null == cached_factory)
+            {
+                cached_factory = factory.memoize().as_anonymous();
+            }
+            return (T) cached_factory();
+        }
+    }
+
+    static public class FuncExtensions
+    {
+        static readonly object mutex = new object();
+
+        static public Func<T> memoize<T>(this Func<T> factory)
+        {
+            var item = default(T);
+
+            return () =>
+            {
+                if (null == item)
+                {
+                    lock (mutex)
+                    {
+                        if (null == item)
+                            item = factory();
+                    }
+                }
+                return item;
+            };
+        }
+
+        static public Func<object> as_anonymous<T>(this Func<T> factory)
+        {
+            return () => factory();
+        }
+    }
+}
\ No newline at end of file
product/application.console/application.console/application.console.csproj
@@ -53,6 +53,7 @@
     <Compile Include="infrastructure\Scope.cs" />
     <Compile Include="infrastructure\SimpleContainer.cs" />
     <Compile Include="infrastructure\SimpleContainerBuilder.cs" />
+    <Compile Include="infrastructure\Singleton.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
product/application.tests/console/infrastructure/SingletonSpecs.cs
@@ -0,0 +1,30 @@
+using System;
+using developwithpassion.bdd.contexts;
+using developwithpassion.bdd.harnesses.mbunit;
+using developwithpassion.bdddoc.core;
+using gorilla.migrations.console.infrastructure;
+
+namespace tests.console.infrastructure
+{
+    public class SingletonSpecs
+    {
+        public abstract class concern : observations_for_a_sut_with_a_contract<Scope, Singleton> {}
+
+        [Concern(typeof (Singleton))]
+        public class when_retrieving_a_singleton_instance : concern
+        {
+            it should_return_the_same_instance_each_time = () =>
+            {
+                Func<TimeStamp> factory = () => new TimeStamp {time = DateTime.Now};
+                var first = controller.sut.apply_to(factory);
+                var second = controller.sut.apply_to(factory);
+                ReferenceEquals(first, second).should_be_true();
+            };
+        }
+
+        public class TimeStamp
+        {
+            public DateTime time { get; set; }
+        }
+    }
+}
\ No newline at end of file
product/application.tests/application.tests.csproj
@@ -70,6 +70,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="console\infrastructure\FactorySpecs.cs" />
+    <Compile Include="console\infrastructure\SingletonSpecs.cs" />
     <Compile Include="console\SimpleContainerSpecs.cs" />
     <Compile Include="core\CommandRegistrySpecs.cs" />
     <Compile Include="core\ConsoleArgumentsSpecs.cs" />