Commit bb37b45

mokhan <mokhan@ce5e1baf-6525-42e4-a1b2-857ea38da20a>
2009-02-26 19:45:47
added the save changes view, and hooked it up to the close project command.
git-svn-id: https://svn.xp-dev.com/svn/mokhan-mo.money@17 ce5e1baf-6525-42e4-a1b2-857ea38da20a
1 parent 4667165
trunk/src/MyMoney/DataAccess/db40/spiking/db40_spike_specs.cs
@@ -2,9 +2,9 @@ using System.Collections.Generic;
 using System.IO;
 using Db4objects.Db4o;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using MyMoney.Utility.Extensions;
 
 namespace MyMoney.DataAccess.db40.spiking
@@ -30,7 +30,7 @@ namespace MyMoney.DataAccess.db40.spiking
                             results = database.Query<ITestObject>().databind();
                         };
 
-        it should_be_able_to_load_the_original_contents = () => results.should_contain(original);
+        it should_be_able_to_load_the_original_contents = () => assertion_extensions.should_contain(results, original);
 
         it they_should_be_equal = () => new TestObject(99, "gretzky").Equals(new TestObject(99, "gretzky"));
 
trunk/src/MyMoney/DataAccess/db40/db4o_repository_specs.cs
@@ -2,9 +2,9 @@ using System.Collections.Generic;
 using Db4objects.Db4o;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.Core;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using assertion_extensions=MyMoney.Testing.spechelpers.core.assertion_extensions;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.DataAccess.db40
@@ -26,8 +26,8 @@ namespace MyMoney.DataAccess.db40
     {
         it should_return_all_the_items_from_the_database = () =>
                                                                {
-                                                                   result.should_contain(first_item);
-                                                                   result.should_contain(second_item);
+                                                                   assertion_extensions.should_contain(result, first_item);
+                                                                   assertion_extensions.should_contain(result, second_item);
                                                                };
 
         context c = () =>
trunk/src/MyMoney/DataAccess/db40/session_factory_specs.cs
@@ -1,9 +1,9 @@
 using Db4objects.Db4o;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Presentation.Model.Projects;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.DataAccess.db40
trunk/src/MyMoney/DataAccess/repositories/bill_repository_specs.cs
@@ -1,14 +1,14 @@
 using System.Collections.Generic;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.accounting.billing;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.spechelpers.contexts;
+using assertion_extensions=MyMoney.Testing.spechelpers.core.assertion_extensions;
 
 namespace MyMoney.DataAccess.repositories
 {
     public class when_loading_all_the_bills_from_the_repository : behaves_like_a_repository
     {
-        it should_return_all_the_bills_in_the_database = () => results.should_contain(first_bill);
+        it should_return_all_the_bills_in_the_database = () => assertion_extensions.should_contain(results, first_bill);
 
         context c = () => { first_bill = an<IBill>(); };
 
trunk/src/MyMoney/Domain/accounting/billing/bill_specs.cs
@@ -1,9 +1,9 @@
 using System;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.Core;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Domain.accounting.billing
 {
trunk/src/MyMoney/Domain/accounting/account_holder_specs.cs
@@ -4,9 +4,9 @@ using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.accounting.billing;
 using MyMoney.Domain.accounting.financial_growth;
 using MyMoney.Domain.Core;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Domain.accounting
@@ -24,8 +24,8 @@ namespace MyMoney.Domain.accounting
     {
         it should_return_all_the_unpaid_bills = () =>
                                                     {
-                                                        result.should_contain(first_unpaid_bill);
-                                                        result.should_contain(second_unpaid_bill);
+                                                        assertion_extensions.should_contain(result, first_unpaid_bill);
+                                                        assertion_extensions.should_contain(result, second_unpaid_bill);
                                                     };
 
         context c = () =>
trunk/src/MyMoney/Domain/accounting/GeneralLedgerSpecs.cs
@@ -3,9 +3,9 @@ using System.Collections.Generic;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.accounting.billing;
 using MyMoney.Domain.Core;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using assertion_extensions=MyMoney.Testing.spechelpers.core.assertion_extensions;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Domain.accounting
@@ -38,12 +38,12 @@ namespace MyMoney.Domain.accounting
     {
         it should_return_all_the_entries_posted_for_that_month = () =>
                                                                      {
-                                                                         result.should_contain(february_first);
-                                                                         result.should_contain(february_twenty_first);
+                                                                         assertion_extensions.should_contain(result, february_first);
+                                                                         assertion_extensions.should_contain(result, february_twenty_first);
                                                                      };
 
         it should_not_return_any_entries_that_were_not_posted_for_that_month =
-            () => result.should_not_contain(april_first);
+            () => assertion_extensions.should_not_contain(result, april_first);
 
         context c = () =>
                         {
trunk/src/MyMoney/Domain/Core/date_specs.cs
@@ -1,7 +1,7 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Domain.Core
 {
@@ -23,7 +23,7 @@ namespace MyMoney.Domain.Core
     [Concern(typeof (date))]
     public class when_an_older_date_is_compared_to_a_younger_date : concerns_for<IDate>
     {
-        it should_return_a_positive_number = () => result.should_be_greater_than(0);
+        it should_return_a_positive_number = () => assertion_extensions.should_be_greater_than(result, 0);
 
         public override IDate create_sut()
         {
trunk/src/MyMoney/Domain/Core/money_extensions_specs.cs
@@ -1,6 +1,6 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Domain.Core
 {
trunk/src/MyMoney/Domain/Core/money_specs.cs
@@ -1,7 +1,7 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Domain.Core
 {
trunk/src/MyMoney/Domain/Core/range_specs.cs
@@ -1,7 +1,7 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Domain.Core
 {
trunk/src/MyMoney/Infrastructure/Container/Windsor/windsor_dependency_registry_specs.cs
@@ -1,9 +1,9 @@
 using Castle.Core;
 using Castle.Windsor;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.Container.Windsor
@@ -14,7 +14,7 @@ namespace MyMoney.Infrastructure.Container.Windsor
         it should_return_the_same_instance_each_time_its_resolved =
             () => result.should_be_the_same_instance_as(sut.find_an_implementation_of<IBird>());
 
-        it should_not_return_null = () => result.should_not_be_null();
+        it should_not_return_null = () => assertion_extensions.should_not_be_null(result);
 
         public override IDependencyRegistry create_sut()
         {
trunk/src/MyMoney/Infrastructure/Container/ResolveSpecs.cs
@@ -2,9 +2,9 @@ using System;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Presentation.Core;
 using MyMoney.Testing;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.Container
trunk/src/MyMoney/Infrastructure/interceptors/lazy_specs.cs
@@ -1,8 +1,8 @@
 using jpboodhoo.bdd.contexts;
 using MyMoney.Infrastructure.Container;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.interceptors
trunk/src/MyMoney/Infrastructure/interceptors/unit_of_work_interceptor.cs
@@ -6,12 +6,13 @@ using MyMoney.Presentation.Model.messages;
 namespace MyMoney.Infrastructure.interceptors
 {
     public interface IUnitOfWorkInterceptor : IInterceptor
-    {}
+    {
+    }
 
     public class unit_of_work_interceptor : IUnitOfWorkInterceptor
     {
-        private readonly IUnitOfWorkRegistry registry;
-        private readonly IEventAggregator broker;
+        readonly IUnitOfWorkRegistry registry;
+        readonly IEventAggregator broker;
 
         public unit_of_work_interceptor(IUnitOfWorkRegistry registry, IEventAggregator broker)
         {
@@ -21,7 +22,8 @@ namespace MyMoney.Infrastructure.interceptors
 
         public void Intercept(IInvocation invocation)
         {
-            using (registry) {
+            using (registry)
+            {
                 invocation.Proceed();
                 registry.commit_all();
                 broker.publish<unsaved_changes_event>();
trunk/src/MyMoney/Infrastructure/Logging/LogSpecs.cs
@@ -1,8 +1,8 @@
 using jpboodhoo.bdd.contexts;
 using MyMoney.Infrastructure.Container;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.Logging
trunk/src/MyMoney/Infrastructure/registries/default_registry_specs.cs
@@ -2,9 +2,9 @@ using System.Collections.Generic;
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.Core;
 using MyMoney.Infrastructure.Container;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using assertion_extensions=MyMoney.Testing.spechelpers.core.assertion_extensions;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.registries
@@ -16,7 +16,7 @@ namespace MyMoney.Infrastructure.registries
         it should_leverage_the_resolver_to_retrieve_all_the_implementations =
             () => mocking_extensions.was_told_to(registry, r => r.all_implementations_of<int>());
 
-        it should_return_the_items_resolved_by_the_registry = () => result.should_contain(24);
+        it should_return_the_items_resolved_by_the_registry = () => assertion_extensions.should_contain(result, 24);
 
         context c = () =>
                         {
trunk/src/MyMoney/Infrastructure/Threading/background_thread_factory_specs.cs
@@ -1,9 +1,9 @@
 using jpboodhoo.bdd.contexts;
 using MyMoney.Infrastructure.Container;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
 using MyMoney.Utility.Core;
+using assertion_extensions=MyMoney.Testing.spechelpers.core.assertion_extensions;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.Threading
@@ -24,7 +24,7 @@ namespace MyMoney.Infrastructure.Threading
 
     public class when_creating_a_background_thread : behaves_like_a_background_thread_factory
     {
-        it should_return_an_instance_of_a_background_thread = () => result.should_not_be_null();
+        it should_return_an_instance_of_a_background_thread = () => assertion_extensions.should_not_be_null(result);
 
         it should_lookup_an_instance_of_the_command_to_execute =
             () => mocking_extensions.was_told_to(registry, r => r.find_an_implementation_of<IDisposableCommand>());
trunk/src/MyMoney/Infrastructure/Threading/timer_factory_specs.cs
@@ -1,9 +1,9 @@
 using System;
 using System.Timers;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Infrastructure.Threading
 {
trunk/src/MyMoney/Infrastructure/transactions/unit_of_work_registry_specs.cs
@@ -1,8 +1,8 @@
 using jpboodhoo.bdd.contexts;
 using MyMoney.Domain.Core;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Infrastructure.transactions
trunk/src/MyMoney/Presentation/Context/the_application_context_specs.cs
@@ -3,9 +3,9 @@ using jpboodhoo.bdd.contexts;
 using MyMoney.Presentation.Model.Menu.File.Commands;
 using MyMoney.Presentation.Presenters.Commands;
 using MyMoney.Presentation.Views.Shell;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using Rhino.Mocks;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
trunk/src/MyMoney/Presentation/Databindings/binding_selector_specs.cs
@@ -1,9 +1,9 @@
 using System;
 using System.Linq.Expressions;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Presentation.Databindings
trunk/src/MyMoney/Presentation/Databindings/ComboBoxDataBindingSpecs.cs
@@ -1,8 +1,8 @@
 using System.Windows.Forms;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Presentation.Databindings
trunk/src/MyMoney/Presentation/Databindings/date_time_property_binding_specs.cs
@@ -1,9 +1,9 @@
 using System;
 using System.Windows.Forms;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Presentation.Databindings
 {
trunk/src/MyMoney/Presentation/Databindings/property_binder_specs.cs
@@ -1,8 +1,8 @@
 using System.Reflection;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Presentation.Databindings
 {
trunk/src/MyMoney/Presentation/Databindings/property_inspector_specs.cs
@@ -1,8 +1,8 @@
 using System.Reflection;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Presentation.Databindings
 {
trunk/src/MyMoney/Presentation/Databindings/TextBoxDataBindingSpecs.cs
@@ -1,8 +1,8 @@
 using System.Windows.Forms;
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
 namespace MyMoney.Presentation.Databindings
trunk/src/MyMoney/Presentation/Model/Menu/File/Commands/close_project_command.cs
@@ -4,7 +4,7 @@ using MyMoney.Utility.Core;
 
 namespace MyMoney.Presentation.Model.Menu.File.Commands
 {
-    public interface ICloseCommand : ICommand
+    public interface ICloseCommand : ICommand, ISaveChangesCallback
     {
     }
 
@@ -12,17 +12,34 @@ namespace MyMoney.Presentation.Model.Menu.File.Commands
     {
         readonly IShell shell;
         readonly IProject project;
+        readonly ISaveChangesCommand command;
 
-        public close_project_command(IShell shell, IProject project)
+        public close_project_command(IShell shell, IProject project, ISaveChangesCommand command)
         {
             this.shell = shell;
+            this.command = command;
             this.project = project;
         }
 
         public void run()
+        {
+            command.run(this);
+        }
+
+        public void saved()
         {
             project.start_a_new_project();
             shell.close_all_windows();
         }
+
+        public void not_saved()
+        {
+            project.start_a_new_project();
+            shell.close_all_windows();
+        }
+
+        public void cancelled()
+        {
+        }
     }
 }
\ No newline at end of file
trunk/src/MyMoney/Presentation/Model/Menu/File/Commands/SaveChangesCommand.cs
@@ -51,6 +51,10 @@ namespace MyMoney.Presentation.Model.Menu.File.Commands
                 view.attach_to(this);
                 view.prompt_user_to_save();
             }
+            else
+            {
+                item.not_saved();
+            }
         }
 
         public void save()
trunk/src/MyMoney/Presentation/Model/messages/unsaved_changes_event.cs
@@ -3,5 +3,6 @@ using MyMoney.Infrastructure.eventing;
 namespace MyMoney.Presentation.Model.messages
 {
     public class unsaved_changes_event : IEvent
-    {}
+    {
+    }
 }
\ No newline at end of file
trunk/src/MyMoney/Presentation/Model/Projects/current_project.cs
@@ -1,13 +1,13 @@
-using System;
 using System.IO;
 using Castle.Core;
 using MyMoney.DataAccess.db40;
 using MyMoney.Infrastructure.eventing;
 using MyMoney.Presentation.Model.messages;
+using MyMoney.Utility.Extensions;
 
 namespace MyMoney.Presentation.Model.Projects
 {
-    public interface IProject
+    public interface IProject : IEventSubscriber<unsaved_changes_event>
     {
         string name();
         void start_a_new_project();
@@ -21,14 +21,16 @@ namespace MyMoney.Presentation.Model.Projects
     [Singleton]
     public class current_project : IProject
     {
-        private readonly IDatabaseConfiguration configuration;
-        private readonly IEventAggregator broker;
-        private IFile current_file;
+        readonly IDatabaseConfiguration configuration;
+        readonly IEventAggregator broker;
+        IFile current_file;
+        bool changes_to_save = false;
 
         public current_project(IDatabaseConfiguration configuration, IEventAggregator broker)
         {
             this.broker = broker;
             this.configuration = configuration;
+            broker.subscribe_to(this);
         }
 
         public string name()
@@ -41,6 +43,7 @@ namespace MyMoney.Presentation.Model.Projects
             if (!file.does_the_file_exist()) return;
             current_file = file;
             configuration.change_path_to(file);
+            changes_to_save = false;
             broker.publish(new new_project_opened(name()));
         }
 
@@ -48,12 +51,14 @@ namespace MyMoney.Presentation.Model.Projects
         {
             current_file = null;
             configuration.change_path_to((file) Path.GetTempFileName());
+            changes_to_save = false;
             broker.publish(new new_project_opened(name()));
         }
 
         public void save_to(IFile new_file)
         {
-            if (string.IsNullOrEmpty(new_file.path)) {
+            if (new_file.path.is_blank())
+            {
                 return;
             }
             current_file = new_file;
@@ -69,19 +74,26 @@ namespace MyMoney.Presentation.Model.Projects
         {
             ensure_that_a_path_to_save_to_has_been_specified();
             configuration.path_to_the_database().copy_to(current_file);
+            changes_to_save = false;
             broker.publish<saved_changes_event>();
         }
 
         public bool has_unsaved_changes()
         {
-            throw new NotImplementedException();
+            return changes_to_save;
         }
 
-        private void ensure_that_a_path_to_save_to_has_been_specified()
+        void ensure_that_a_path_to_save_to_has_been_specified()
         {
-            if (!has_been_saved_at_least_once()) {
+            if (!has_been_saved_at_least_once())
+            {
                 throw new file_not_specified_exception();
             }
         }
+
+        public void notify(unsaved_changes_event message)
+        {
+            changes_to_save = true;
+        }
     }
 }
\ No newline at end of file
trunk/src/MyMoney/Presentation/Model/Projects/current_project_specs.cs
@@ -2,11 +2,11 @@ using System;
 using jpboodhoo.bdd.contexts;
 using MyMoney.DataAccess.db40;
 using MyMoney.Infrastructure.eventing;
+using MyMoney.Presentation.Model.messages;
 using MyMoney.Testing;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
-using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Presentation.Model.Projects
 {
@@ -31,15 +31,17 @@ namespace MyMoney.Presentation.Model.Projects
     public class when_saving_the_current_project : behaves_like_a_project
     {
         it should_save_the_current_database_to_the_path_specified_by_the_user =
-            () => mocking_extensions.was_told_to(current_file, x => x.copy_to(file_to_update));
+            () => current_file.was_told_to(x => x.copy_to(file_to_update));
 
         context c = () =>
                         {
                             file_to_update = an<IFile>();
                             current_file = an<IFile>();
 
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(configuration), x => x.path_to_the_database()), current_file);
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(file_to_update), x => x.does_the_file_exist()), true);
+                            when_the(configuration).is_told_to(x => x.path_to_the_database()).
+                                it_will_return(current_file);
+                            when_the(file_to_update).is_told_to(x => x.does_the_file_exist()).
+                                it_will_return(true);
                         };
 
         because b = () =>
@@ -64,7 +66,8 @@ namespace MyMoney.Presentation.Model.Projects
 
     public class when_specifying_a_new_path_to_save_an_opened_project_to : behaves_like_a_project
     {
-        it should_save_the_current_database_to_the_new_path = () => mocking_extensions.was_told_to(database_file, x => x.copy_to(new_file));
+        it should_save_the_current_database_to_the_new_path =
+            () => database_file.was_told_to(x => x.copy_to(new_file));
 
         context c = () =>
                         {
@@ -72,8 +75,9 @@ namespace MyMoney.Presentation.Model.Projects
                             new_file = an<IFile>();
                             database_file = an<IFile>();
 
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(configuration), x => x.path_to_the_database()), database_file);
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(new_file), x => x.path), "blah");
+                            when_the(configuration).is_told_to(x => x.path_to_the_database()).
+                                it_will_return(database_file);
+                            when_the(new_file).is_told_to(x => x.path).it_will_return("blah");
                         };
 
         because b = () =>
@@ -94,7 +98,7 @@ namespace MyMoney.Presentation.Model.Projects
         context c = () =>
                         {
                             invalid_file = an<IFile>();
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(invalid_file), x => x.does_the_file_exist()), false);
+                            when_the(invalid_file).is_told_to(x => x.does_the_file_exist()).it_will_return(false);
                         };
 
         because b = () =>
@@ -115,7 +119,7 @@ namespace MyMoney.Presentation.Model.Projects
                         {
                             invalid_file = an<IFile>();
 
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(invalid_file), x => x.path), string.Empty);
+                            when_the(invalid_file).is_told_to(x => x.path).it_will_return(string.Empty);
                         };
 
         because b = () =>
@@ -133,12 +137,43 @@ namespace MyMoney.Presentation.Model.Projects
         context c = () =>
                         {
                             file = an<IFile>();
-
-                            mocking_extensions.it_will_return(mocking_extensions.is_told_to(when_the(file), x => x.does_the_file_exist()), true);
+                            when_the(file).is_told_to(x => x.does_the_file_exist()).it_will_return(true);
                         };
 
         because b = () => sut.open(file);
 
         static IFile file;
     }
+
+    public class when_checking_if_there_are_any_unsaved_changes_and_a_project_is_not_open : behaves_like_a_project
+    {
+        it should_return_false = () => result.should_be_equal_to(false);
+
+        because b = () => { result = sut.has_unsaved_changes(); };
+
+        static bool result;
+    }
+
+    public class when_checking_if_there_are_any_unsaved_changes_and_there_are : behaves_like_a_project
+    {
+        it should_return_true = () => result.should_be_true();
+
+        context c = () =>
+                        {
+                            file = an<IFile>();
+                            message = new unsaved_changes_event();
+                        };
+
+        because b = () =>
+                        {
+                            sut.start_a_new_project();
+                            sut.save_to(file);
+                            sut.notify(message);
+                            result = sut.has_unsaved_changes();
+                        };
+
+        static bool result;
+        static IFile file;
+        static unsaved_changes_event message;
+    }
 }
\ No newline at end of file
trunk/src/MyMoney/Testing/spechelpers/core/assertion_extensions.cs
@@ -4,7 +4,7 @@ using System.Linq;
 using JetBrains.Annotations;
 using MbUnit.Framework;
 
-namespace MyMoney.Testing.Extensions
+namespace MyMoney.Testing.spechelpers.core
 {
     public static class assertion_extensions
     {
@@ -41,31 +41,73 @@ namespace MyMoney.Testing.Extensions
         [AssertionMethod]
         public static void should_contain<T>(this IEnumerable<T> items_to_peek_in_to, T items_to_look_for)
         {
-            Assert.IsTrue(items_to_peek_in_to.Contains(items_to_look_for));
+            items_to_peek_in_to.Contains(items_to_look_for).should_be_true();
         }
 
         [AssertionMethod]
         public static void should_not_contain<T>(this IEnumerable<T> items_to_peek_into, T item_to_look_for)
         {
-            Assert.IsFalse(items_to_peek_into.Contains(item_to_look_for));
+            items_to_peek_into.Contains(item_to_look_for).should_be_false();
         }
 
         [AssertionMethod]
         public static void should_be_an_instance_of<T>(this object item)
         {
-            Assert.IsInstanceOfType(typeof (T), item);
+            item.should_be_an_instance_of(typeof (T));
+        }
+
+        [AssertionMethod]
+        public static void should_be_an_instance_of(this object item, Type type)
+        {
+            Assert.IsInstanceOfType(type, item);
         }
 
         [AssertionMethod]
         public static void should_have_thrown<TheException>(this Action action) where TheException : Exception
         {
-            try {
+            try
+            {
                 action();
                 Assert.Fail("the_exception_was_not_thrown");
             }
-            catch (Exception e) {
-                e.should_be_an_instance_of<TheException>();
+            catch (Exception e)
+            {
+                should_be_an_instance_of<TheException>(e);
             }
         }
+
+        [AssertionMethod]
+        public static void should_be_true(this bool item)
+        {
+            Assert.IsTrue(item);
+        }
+
+        [AssertionMethod]
+        public static void should_be_false(this bool item)
+        {
+            Assert.IsFalse(item);
+        }
+
+        [AssertionMethod]
+        public static void should_contain<T>(this IEnumerable<T> items, params T[] items_to_find)
+        {
+            foreach (var item_to_find in items_to_find)
+            {
+                items.should_contain(item_to_find);
+            }
+        }
+
+        [AssertionMethod]
+        public static void should_only_contain<T>(this IEnumerable<T> items, params T[] itemsToFind)
+        {
+            items.Count().should_be_equal_to(itemsToFind.Length);
+            items.should_contain(itemsToFind);
+        }
+
+        [AssertionMethod]
+        public static void should_be_equal_ignoring_case(this string item, string other)
+        {
+            StringAssert.AreEqualIgnoreCase(item, other);
+        }
     }
 }
\ No newline at end of file
trunk/src/MyMoney/Testing/spechelpers/core/BDDAssertions.cs
@@ -1,73 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using MbUnit.Framework;
-
-namespace MyMoney.Testing.spechelpers.core
-{
-    public static class BDDAssertions
-    {
-        public static void should_be_equal_ignoring_case(this string item, string other)
-        {
-            StringAssert.AreEqualIgnoreCase(item, other);
-        }
-
-        public static void should_be_equal_to<T>(this T item, T result)
-        {
-            Assert.AreEqual(result, item);
-        }
-
-        public static void should_not_be_null<T>(this T item) where T : class
-        {
-            Assert.IsNotNull(item);
-        }
-
-        public static void should_be_true(this bool item)
-        {
-            Assert.IsTrue(item);
-        }
-
-        public static void should_be_false(this bool item)
-        {
-            Assert.IsFalse(item);
-        }
-
-        public static void should_be_an_instance_of(this object item, Type type)
-        {
-            Assert.IsInstanceOfType(type, item);
-        }
-
-        public static void should_be_an_instance_of<Item>(this object item)
-        {
-            item.should_be_an_instance_of(typeof (Item));
-        }
-
-        public static void should_be_greater_than<T>(this T item, T value) where T : IComparable
-        {
-            Assert.GreaterThan(item, value);
-        }
-
-        public static void should_not_contain<T>(this IEnumerable<T> items, T item)
-        {
-            items.Contains(item).should_be_false();
-        }
-
-        public static void should_contain<T>(this IEnumerable<T> items, T item)
-        {
-            items.Contains(item).should_be_true();
-        }
-
-        public static void should_contain<T>(this IEnumerable<T> items, params T[] itemsToFind)
-        {
-            foreach (var itemToFind in itemsToFind) {
-                items.should_contain(itemToFind);
-            }
-        }
-
-        public static void should_only_contain<T>(this IEnumerable<T> items, params T[] itemsToFind)
-        {
-            items.Count().should_be_equal_to(itemsToFind.Length);
-            items.should_contain(itemsToFind);
-        }
-    }
-}
\ No newline at end of file
trunk/src/MyMoney/Utility/Extensions/mapping_extensions_specs.cs
@@ -1,7 +1,7 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.MetaData;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 using MyMoney.Utility.Core;
 using mocking_extensions=MyMoney.Testing.spechelpers.core.mocking_extensions;
 
trunk/src/MyMoney/Utility/Extensions/numeric_conversions_specs.cs
@@ -1,6 +1,6 @@
 using jpboodhoo.bdd.contexts;
-using MyMoney.Testing.Extensions;
 using MyMoney.Testing.spechelpers.contexts;
+using MyMoney.Testing.spechelpers.core;
 
 namespace MyMoney.Utility.Extensions
 {
trunk/src/MyMoney/MyMoney.csproj
@@ -425,7 +425,6 @@
     <Compile Include="Testing\spechelpers\core\IHideObjectMembers.cs" />
     <Compile Include="Testing\spechelpers\core\method_call_occurance.cs" />
     <Compile Include="Testing\MetaData\run_in_real_container.cs" />
-    <Compile Include="Testing\spechelpers\core\BDDAssertions.cs" />
     <Compile Include="Utility\Core\chained_mapper.cs" />
     <Compile Include="Utility\Core\and_specification.cs" />
     <Compile Include="Utility\Core\command.cs" />