main
  1using System;
  2using System.Collections.Generic;
  3using developwithpassion.bdd.contexts;
  4using Gorilla.Commons.Testing;
  5using gorilla.commons.utility;
  6
  7namespace momoney.database.transactions
  8{
  9    public class SessionSpecs
 10    {
 11        public class behaves_like_session : concerns_for<ISession, Session>
 12        {
 13            context c = () =>
 14            {
 15                transaction = the_dependency<ITransaction>();
 16                database = the_dependency<IDatabase>();
 17            };
 18
 19            static protected ITransaction transaction;
 20            static protected IDatabase database;
 21        }
 22
 23        [Concern(typeof (Session))]
 24        public class when_saving_a_transient_item_to_a_session : behaves_like_session
 25        {
 26            it should_add_the_entity_to_the_identity_map = () => map.was_told_to(x => x.add(guid, entity));
 27
 28            context c = () =>
 29            {
 30                guid = Guid.NewGuid();
 31                entity = an<ITestEntity>();
 32                map = an<IIdentityMap<Guid, ITestEntity>>();
 33
 34                when_the(entity).is_told_to(x => x.id).it_will_return(guid);
 35                when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(map);
 36            };
 37
 38            because b = () => sut.save(entity);
 39
 40            static ITestEntity entity;
 41            static IIdentityMap<Guid, ITestEntity> map;
 42            static Id<Guid> guid;
 43        }
 44
 45        [Concern(typeof (Session))]
 46        public class when_commiting_the_changes_made_in_a_session : behaves_like_session
 47        {
 48            it should_commit_all_the_changes_from_the_running_transaction =
 49                () => transaction.was_told_to(x => x.commit_changes());
 50
 51            it should_not_rollback_any_changes_from_the_running_transaction =
 52                () => transaction.was_not_told_to(x => x.rollback_changes());
 53
 54            because b = () =>
 55            {
 56                sut.flush();
 57                sut.Dispose();
 58            };
 59        }
 60
 61        [Concern(typeof (Session))]
 62        public class when_closing_a_session_before_flushing_the_changes : behaves_like_session
 63        {
 64            it should_rollback_any_changes_made_in_the_current_transaction =
 65                () => transaction.was_told_to(x => x.rollback_changes());
 66
 67            because b = () => sut.Dispose();
 68        }
 69
 70        [Concern(typeof (Session))]
 71        public class when_loading_all_instances_of_a_certain_type_and_some_have_already_been_loaded : behaves_like_session
 72        {
 73            it should_return_the_items_from_the_cache = () => results.should_contain(cached_item);
 74
 75            it should_exclude_duplicates_from_the_database = () => results.should_not_contain(database_item);
 76
 77            it should_add_items_from_the_database_to_the_identity_map =
 78                () => identity_map.was_told_to(x => x.add(id_of_the_uncached_item, uncached_item));
 79
 80            context c = () =>
 81            {
 82                id = Guid.NewGuid();
 83                id_of_the_uncached_item = Guid.NewGuid();
 84                identity_map = an<IIdentityMap<Guid, ITestEntity>>();
 85                cached_item = an<ITestEntity>();
 86                database_item = an<ITestEntity>();
 87                uncached_item = an<ITestEntity>();
 88
 89                when_the(cached_item).is_told_to(x => x.id).it_will_return(id);
 90                when_the(database_item).is_told_to(x => x.id).it_will_return(id);
 91                when_the(uncached_item).is_told_to(x => x.id).it_will_return(id_of_the_uncached_item);
 92                when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(identity_map);
 93                when_the(identity_map).is_told_to(x => x.contains_an_item_for(id)).it_will_return(true);
 94                when_the(identity_map).is_told_to(x => x.all()).it_will_return(cached_item);
 95                when_the(database).is_told_to(x => x.fetch_all<ITestEntity>())
 96                    .it_will_return(database_item, uncached_item);
 97            };
 98
 99            because b = () =>
100            {
101                sut.find<ITestEntity>(id);
102                results = sut.all<ITestEntity>();
103            };
104
105            static IEnumerable<ITestEntity> results;
106            static Id<Guid> id;
107            static Id<Guid> id_of_the_uncached_item;
108            static ITestEntity cached_item;
109            static ITestEntity database_item;
110            static IIdentityMap<Guid, ITestEntity> identity_map;
111            static ITestEntity uncached_item;
112        }
113
114        [Concern(typeof (Session))]
115        public class when_looking_up_a_specific_entity_by_its_id_and_it_has_not_been_loaded_into_the_cache :
116            behaves_like_session
117        {
118            it should_return_that_item = () =>
119            {
120                result.should_be_equal_to(correct_item);
121            };
122
123            it should_add_that_item_to_the_identity_map = () => map.was_told_to(x => x.add(id, correct_item));
124
125            context c = () =>
126            {
127                id = Guid.NewGuid();
128                wrong_item = an<ITestEntity>();
129                correct_item = an<ITestEntity>();
130                map = an<IIdentityMap<Guid, ITestEntity>>();
131                when_the(wrong_item).is_told_to(x => x.id).it_will_return<Id<Guid>>(Guid.NewGuid());
132                when_the(correct_item).is_told_to(x => x.id).it_will_return(id);
133                when_the(database)
134                    .is_told_to(x => x.fetch_all<ITestEntity>())
135                    .it_will_return(wrong_item, correct_item);
136                when_the(transaction).is_told_to(x => x.create_for<ITestEntity>())
137                    .it_will_return(map);
138            };
139
140            because b = () =>
141            {
142                result = sut.find<ITestEntity>(id);
143            };
144
145            static Id<Guid> id;
146            static Identifiable<Guid> result;
147            static ITestEntity correct_item;
148            static ITestEntity wrong_item;
149            static IIdentityMap<Guid, ITestEntity> map;
150        }
151
152        [Concern(typeof (Session))]
153        public class when_deleting_an_item_from_the_database : behaves_like_session
154        {
155            it should_remove_that_item_from_the_cache = () => map.was_told_to(x => x.evict(id));
156
157            context c = () =>
158            {
159                id = Guid.NewGuid();
160                entity = an<ITestEntity>();
161                map = an<IIdentityMap<Guid, ITestEntity>>();
162
163                when_the(entity).is_told_to(x => x.id).it_will_return(id);
164                when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(map);
165                when_the(database).is_told_to(x => x.fetch_all<ITestEntity>()).it_will_return(entity);
166            };
167
168            because b = () =>
169            {
170                sut.find<ITestEntity>(id);
171                sut.delete(entity);
172            };
173
174            static Id<Guid> id;
175            static IIdentityMap<Guid, ITestEntity> map;
176            static ITestEntity entity;
177        }
178
179        public interface ITestEntity : Identifiable<Guid> {}
180    }
181}