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}