Commit 6ca99da

unknown <mo@.(none)>
2009-10-09 21:19:36
implemented the run migrations command
1 parent 52f365a
product/application/data/DatabaseGateway.cs
@@ -0,0 +1,7 @@
+namespace simple.migrations.Data
+{
+    public interface DatabaseGateway
+    {
+        void run(SqlFile file);
+    }
+}
\ No newline at end of file
product/application/data/DatabaseGatewayFactory.cs
@@ -0,0 +1,7 @@
+namespace simple.migrations.Data
+{
+    public interface DatabaseGatewayFactory
+    {
+        DatabaseGateway gateway_to(string connection_string, string database_provider);
+    }
+}
\ No newline at end of file
product/application/data/SqlFile.cs
@@ -0,0 +1,4 @@
+namespace simple.migrations.Data
+{
+    public class SqlFile {}
+}
\ No newline at end of file
product/application/io/FileSystem.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using simple.migrations.Data;
+
+namespace simple.migrations.io
+{
+    public interface FileSystem
+    {
+        IEnumerable<SqlFile> all_sql_files_from(string directory);
+    }
+}
\ No newline at end of file
product/application/Properties/AssemblyInfo.cs
@@ -1,10 +1,10 @@
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
+
 [assembly: AssemblyTitle("application")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
 // Setting ComVisible to false makes the types in this assembly not visible 
 // to COM components.  If you need to access a type in this assembly from 
 // COM, set the ComVisible attribute to true on that type.
+
 [assembly: ComVisible(false)]
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
+
 [assembly: Guid("39509bf4-9c16-4b87-96eb-cfa67f0cfb7e")]
 
 // Version information for an assembly consists of the following four values:
@@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
+
 [assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
product/application/utility/IterationExtensions.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+
+namespace simple.migrations.utility
+{
+    static public class IterationExtensions
+    {
+        static public void each<T>(this IEnumerable<T> items, Action<T> visitor)
+        {
+            foreach (var item in items) visitor(item);
+        }
+    }
+}
\ No newline at end of file
product/application/application.csproj
@@ -52,11 +52,16 @@
     <Compile Include="ConsoleArguments.cs" />
     <Compile Include="ConsoleArgumentsCommandRegistry.cs" />
     <Compile Include="ConsoleCommand.cs" />
+    <Compile Include="data\DatabaseGateway.cs" />
+    <Compile Include="data\DatabaseGatewayFactory.cs" />
+    <Compile Include="data\SqlFile.cs" />
     <Compile Include="HelpCommand.cs" />
+    <Compile Include="io\FileSystem.cs" />
     <Compile Include="ParameterizedCommand.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RunMigrationsCommand.cs" />
     <Compile Include="StringExtensions.cs" />
+    <Compile Include="utility\IterationExtensions.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
product/application/ConsoleArguments.cs
@@ -18,18 +18,28 @@ namespace simple.migrations
 
         public virtual bool contains(string key)
         {
-            return arguments[0].Contains(key);
+            return find_match_for(key).Success;
         }
 
         public virtual string parse_for(string argument_name)
         {
-            var pattern = @"-{0}:'.+?'".format_using(argument_name);
-            var argument = arguments[0];
-            var match = new Regex(pattern, RegexOptions.Singleline).Match(argument);
+            var match = find_match_for(argument_name);
+            return value_from(argument_name, match);
+        }
+
+        string value_from(string argument_name, Capture match)
+        {
             var replace = match.Value.Replace("-{0}:'".format_using(argument_name), "");
             return replace.Remove(replace.Length - 1, 1);
         }
 
+        Match find_match_for(string argument_name)
+        {
+            var pattern = @"-{0}:'.+?'".format_using(argument_name);
+            var argument = arguments[0];
+            return new Regex(pattern, RegexOptions.Singleline).Match(argument);
+        }
+
         public bool Equals(ConsoleArguments other)
         {
             if (ReferenceEquals(null, other)) return false;
product/application/RunMigrationsCommand.cs
@@ -1,12 +1,26 @@
-using System;
+using simple.migrations.Data;
+using simple.migrations.io;
+using simple.migrations.utility;
 
 namespace simple.migrations
 {
     public class RunMigrationsCommand : ConsoleCommand
     {
+        FileSystem file_system;
+        DatabaseGatewayFactory gateway_factory;
+
+        public RunMigrationsCommand(FileSystem file_system, DatabaseGatewayFactory gateway_factory)
+        {
+            this.file_system = file_system;
+            this.gateway_factory = gateway_factory;
+        }
+
         public void run_against(ConsoleArguments arguments)
         {
-            throw new NotImplementedException();
+            var gateway = gateway_factory.gateway_to(arguments.parse_for("connection_string"), arguments.parse_for("data_provider"));
+            file_system
+                .all_sql_files_from(arguments.parse_for("migrations_dir"))
+                .each(x => gateway.run(x));
         }
 
         public bool can_handle(ConsoleArguments arguments)
product/application.tests/helpers/RhinoStubbingExtensions.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using Rhino.Mocks;
+using Rhino.Mocks.Interfaces;
+
+namespace tests.helpers
+{
+    static public class RhinoStubbingExtensions
+    {
+        static public IMethodOptions<T> it_will_return<T>(this IMethodOptions<T> options, T item)
+        {
+            return options.Return(item);
+        }
+
+        static public IMethodOptions<IEnumerable<T>> it_will_return<T>(this IMethodOptions<IEnumerable<T>> options, params T[] items)
+        {
+            return options.Return(new List<T>(items));
+        }
+
+        static public IMethodOptions<IEnumerable<T>> it_will_return_nothing<T>(this IMethodOptions<IEnumerable<T>> options)
+        {
+            return options.it_will_return();
+        }
+
+        static public IMethodOptions<R> is_told_to<T, R>(this T item, Function<T, R> action) where T : class
+        {
+            return item.Stub(action);
+        }
+    }
+}
\ No newline at end of file
product/application.tests/application.tests.csproj
@@ -73,6 +73,7 @@
     <Compile Include="ConsoleArgumentsSpecs.cs" />
     <Compile Include="ConsoleSpecs.cs" />
     <Compile Include="EmptyTestFixture.cs" />
+    <Compile Include="helpers\RhinoStubbingExtensions.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RunMigrationsCommandSpecs.cs" />
   </ItemGroup>
product/application.tests/RunMigrationsCommandSpecs.cs
@@ -1,6 +1,11 @@
 using developwithpassion.bdd.contexts;
 using developwithpassion.bdd.harnesses.mbunit;
+using developwithpassion.bdd.mocking.rhino;
+using developwithpassion.bdddoc.core;
 using simple.migrations;
+using simple.migrations.Data;
+using simple.migrations.io;
+using tests.helpers;
 
 namespace tests
 {
@@ -8,20 +13,32 @@ namespace tests
     {
         public class concern : observations_for_a_sut_with_a_contract<ConsoleCommand, RunMigrationsCommand>
         {
+            context c = () =>
+            {
+                file_system = the_dependency<FileSystem>();
+                database_gateway_factory=the_dependency<DatabaseGatewayFactory>();
+            };
+
+            static protected FileSystem file_system;
+            static protected DatabaseGatewayFactory database_gateway_factory;
         }
 
+        [Concern(typeof (RunMigrationsCommand))]
         public class when_the_proper_arguments_are_specified_to_run_the_database_migrations : concern
         {
             context c = () =>
-                            {
-                                proper_arguments =
-                                    new[]
-                                        {
-                                            "-migrations_dir:'c:\\tmp' -connection_string:'Server=(local);Database=test;Integrated Security=True;' -data_provider:'System.Data.SqlClient'"
-                                        };
-                            };
+            {
+                proper_arguments =
+                    new[]
+                    {
+                        "-migrations_dir:'c:\\tmp' -connection_string:'Server=(local);Database=test;Integrated Security=True;' -data_provider:'System.Data.SqlClient'"
+                    };
+            };
 
-            because b = () => { result = sut.can_handle(proper_arguments); };
+            because b = () =>
+            {
+                result = sut.can_handle(proper_arguments);
+            };
 
             it should_recognize_the_arguments = () => result.should_be_true();
 
@@ -29,11 +46,18 @@ namespace tests
             static bool result;
         }
 
+        [Concern(typeof (RunMigrationsCommand))]
         public class when_unknown_arguments_are_specified : concern
         {
-            context c = () => { unknown_arguments = new[] {""}; };
+            context c = () =>
+            {
+                unknown_arguments = new[] {""};
+            };
 
-            because b = () => { result = sut.can_handle(unknown_arguments); };
+            because b = () =>
+            {
+                result = sut.can_handle(unknown_arguments);
+            };
 
             it should_not_recognize_the_arguments_to_run_the_database_migrations = () => result.should_be_false();
 
@@ -41,5 +65,43 @@ namespace tests
 
             static bool result;
         }
+
+        [Concern(typeof (RunMigrationsCommand))]
+        public class When_the_migrations_command_is_run : concern
+        {
+            context c = () =>
+            {
+                old_migration = an<SqlFile>();
+                new_migration = an<SqlFile>();
+                arguments = an<ConsoleArguments>();
+                gateway = an<DatabaseGateway>();
+
+                database_gateway_factory
+                    .is_told_to(x => x.gateway_to("blah=blah;","System.Data.SqlClient"))
+                    .it_will_return(gateway);
+                file_system
+                    .is_told_to(x => x.all_sql_files_from("c:\\tmp"))
+                    .it_will_return(old_migration, new_migration);
+
+                arguments.is_told_to(x => x.parse_for("migrations_dir")).it_will_return("c:\\tmp");
+                arguments.is_told_to(x => x.parse_for("connection_string")).it_will_return("blah=blah;");
+                arguments.is_told_to(x => x.parse_for("data_provider")).it_will_return("System.Data.SqlClient");
+            };
+
+            because b = () =>
+            {
+                sut.run_against(arguments);
+            };
+
+            it should_run_each_migration_script = () =>
+            {
+                gateway.received(x => x.run(new_migration));
+            };
+
+            static SqlFile new_migration;
+            static SqlFile old_migration;
+            static ConsoleArguments arguments;
+            static DatabaseGateway gateway;
+        }
     }
 }
\ No newline at end of file