Commit 6ca99da
Changed files (12)
product
application
application.tests
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