a tiny mvc framework for php using php-activerecord
1<?php
2include 'helpers/config.php';
3
4class CallBackTest extends DatabaseTest
5{
6 public function set_up($connection_name=null)
7 {
8 parent::set_up($connection_name);
9
10 // ensure VenueCB model has been loaded
11 VenueCB::find(1);
12
13 $this->callback = new ActiveRecord\CallBack('VenueCB');
14 }
15
16 public function assert_has_callback($callback_name, $method_name=null)
17 {
18 if (!$method_name)
19 $method_name = $callback_name;
20
21 $this->assert_true(in_array($method_name,$this->callback->get_callbacks($callback_name)));
22 }
23
24 public function assert_implicit_save($first_method, $second_method)
25 {
26 $i_ran = array();
27 $this->callback->register($first_method,function($model) use (&$i_ran, $first_method) { $i_ran[] = $first_method; });
28 $this->callback->register($second_method,function($model) use (&$i_ran, $second_method) { $i_ran[] = $second_method; });
29 $this->callback->invoke(null,$second_method);
30 $this->assert_equals(array($first_method,$second_method),$i_ran);
31 }
32
33 public function test_generic_callback_was_auto_registered()
34 {
35 $this->assert_has_callback('after_construct');
36 }
37
38 public function test_register()
39 {
40 $this->callback->register('after_construct');
41 $this->assert_has_callback('after_construct');
42 }
43
44 public function test_register_non_generic()
45 {
46 $this->callback->register('after_construct','non_generic_after_construct');
47 $this->assert_has_callback('after_construct','non_generic_after_construct');
48 }
49
50 /**
51 * @expectedException ActiveRecord\ActiveRecordException
52 */
53 public function test_register_invalid_callback()
54 {
55 $this->callback->register('invalid_callback');
56 }
57
58 /**
59 * @expectedException ActiveRecord\ActiveRecordException
60 */
61 public function test_register_callback_with_undefined_method()
62 {
63 $this->callback->register('after_construct','do_not_define_me');
64 }
65
66 public function test_register_with_string_definition()
67 {
68 $this->callback->register('after_construct','after_construct');
69 $this->assert_has_callback('after_construct');
70 }
71
72 public function test_register_with_closure()
73 {
74 $this->callback->register('after_construct',function($mode) { });
75 }
76
77 public function test_register_with_null_definition()
78 {
79 $this->callback->register('after_construct',null);
80 $this->assert_has_callback('after_construct');
81 }
82
83 public function test_register_with_no_definition()
84 {
85 $this->callback->register('after_construct');
86 $this->assert_has_callback('after_construct');
87 }
88
89 public function test_register_appends_to_registry()
90 {
91 $this->callback->register('after_construct');
92 $this->callback->register('after_construct','non_generic_after_construct');
93 $this->assert_equals(array('after_construct','after_construct','non_generic_after_construct'),$this->callback->get_callbacks('after_construct'));
94 }
95
96 public function test_register_prepends_to_registry()
97 {
98 $this->callback->register('after_construct');
99 $this->callback->register('after_construct','non_generic_after_construct',array('prepend' => true));
100 $this->assert_equals(array('non_generic_after_construct','after_construct','after_construct'),$this->callback->get_callbacks('after_construct'));
101 }
102
103 public function test_registers_via_static_array_definition()
104 {
105 $this->assert_has_callback('after_destroy','after_destroy_one');
106 $this->assert_has_callback('after_destroy','after_destroy_two');
107 }
108
109 public function test_registers_via_static_string_definition()
110 {
111 $this->assert_has_callback('before_destroy','before_destroy_using_string');
112 }
113
114 /**
115 * @expectedException ActiveRecord\ActiveRecordException
116 */
117 public function test_register_via_static_with_invalid_definition()
118 {
119 $class_name = "Venues_" . md5(uniqid());
120 eval("class $class_name extends ActiveRecord\\Model { static \$table_name = 'venues'; static \$after_save = 'method_that_does_not_exist'; };");
121 new $class_name();
122 new ActiveRecord\CallBack($class_name);
123 }
124
125 public function test_can_register_same_multiple_times()
126 {
127 $this->callback->register('after_construct');
128 $this->callback->register('after_construct');
129 $this->assert_equals(array('after_construct','after_construct','after_construct'),$this->callback->get_callbacks('after_construct'));
130 }
131
132 public function test_register_closure_callback()
133 {
134 $closure = function($model) {};
135 $this->callback->register('after_save',$closure);
136 $this->assert_equals(array($closure),$this->callback->get_callbacks('after_save'));
137 }
138
139 public function test_get_callbacks_returns_array()
140 {
141 $this->callback->register('after_construct');
142 $this->assert_true(is_array($this->callback->get_callbacks('after_construct')));
143 }
144
145 public function test_get_callbacks_returns_null()
146 {
147 $this->assert_null($this->callback->get_callbacks('this_callback_name_should_never_exist'));
148 }
149
150 public function test_invoke_runs_all_callbacks()
151 {
152 $mock = $this->get_mock('VenueCB',array('after_destroy_one','after_destroy_two'));
153 $mock->expects($this->once())->method('after_destroy_one');
154 $mock->expects($this->once())->method('after_destroy_two');
155 $this->callback->invoke($mock,'after_destroy');
156 }
157
158 public function test_invoke_closure()
159 {
160 $i_ran = false;
161 $this->callback->register('after_validation',function($model) use (&$i_ran) { $i_ran = true; });
162 $this->callback->invoke(null,'after_validation');
163 $this->assert_true($i_ran);
164 }
165
166 public function test_invoke_implicitly_calls_save_first()
167 {
168 $this->assert_implicit_save('before_save','before_create');
169 $this->assert_implicit_save('before_save','before_update');
170 $this->assert_implicit_save('after_save','after_create');
171 $this->assert_implicit_save('after_save','after_update');
172 }
173
174 /**
175 * @expectedException ActiveRecord\ActiveRecordException
176 */
177 public function test_invoke_unregistered_callback()
178 {
179 $mock = $this->get_mock('VenueCB', array('columns'));
180 $this->callback->invoke($mock,'before_validation_on_create');
181 }
182
183 public function test_before_callbacks_pass_on_false_return_callback_returned_false()
184 {
185 $this->callback->register('before_validation',function($model) { return false; });
186 $this->assert_false($this->callback->invoke(null,'before_validation'));
187 }
188
189 public function test_before_callbacks_does_not_pass_on_false_for_after_callbacks()
190 {
191 $this->callback->register('after_validation',function($model) { return false; });
192 $this->assert_true($this->callback->invoke(null,'after_validation'));
193 }
194
195 public function test_gh_28_after_create_should_be_invoked_after_auto_incrementing_pk_is_set()
196 {
197 $that = $this;
198 VenueCB::$after_create = function($model) use ($that) { $that->assert_not_null($model->id); };
199 ActiveRecord\Table::clear_cache('VenueCB');
200 $venue = VenueCB::find(1);
201 $venue = new VenueCB($venue->attributes());
202 $venue->id = null;
203 $venue->name = 'alksdjfs';
204 $venue->save();
205 }
206
207 public function test_before_create_returned_false_halts_execution()
208 {
209 VenueCB::$before_create = array('before_create_halt_execution');
210 ActiveRecord\Table::clear_cache('VenueCB');
211 $table = ActiveRecord\Table::load('VenueCB');
212
213 $i_ran = false;
214 $i_should_have_ran = false;
215 $table->callback->register('before_save', function($model) use (&$i_should_have_ran) { $i_should_have_ran = true; });
216 $table->callback->register('before_create',function($model) use (&$i_ran) { $i_ran = true; });
217 $table->callback->register('after_create',function($model) use (&$i_ran) { $i_ran = true; });
218
219 $v = VenueCB::find(1);
220 $v->id = null;
221 VenueCB::create($v->attributes());
222
223 $this->assert_true($i_should_have_ran);
224 $this->assert_false($i_ran);
225 $this->assert_true(strpos(ActiveRecord\Table::load('VenueCB')->last_sql, 'INSERT') === false);
226 }
227
228 public function test_before_save_returned_false_halts_execution()
229 {
230 VenueCB::$before_update = array('before_update_halt_execution');
231 ActiveRecord\Table::clear_cache('VenueCB');
232 $table = ActiveRecord\Table::load('VenueCB');
233
234 $i_ran = false;
235 $i_should_have_ran = false;
236 $table->callback->register('before_save', function($model) use (&$i_should_have_ran) { $i_should_have_ran = true; });
237 $table->callback->register('before_update',function($model) use (&$i_ran) { $i_ran = true; });
238 $table->callback->register('after_save',function($model) use (&$i_ran) { $i_ran = true; });
239
240 $v = VenueCB::find(1);
241 $v->name .= 'test';
242 $ret = $v->save();
243
244 $this->assert_true($i_should_have_ran);
245 $this->assert_false($i_ran);
246 $this->assert_false($ret);
247 $this->assert_true(strpos(ActiveRecord\Table::load('VenueCB')->last_sql, 'UPDATE') === false);
248 }
249
250 public function test_before_destroy_returned_false_halts_execution()
251 {
252 VenueCB::$before_destroy = array('before_destroy_halt_execution');
253 ActiveRecord\Table::clear_cache('VenueCB');
254 $table = ActiveRecord\Table::load('VenueCB');
255
256 $i_ran = false;
257 $table->callback->register('before_destroy',function($model) use (&$i_ran) { $i_ran = true; });
258 $table->callback->register('after_destroy',function($model) use (&$i_ran) { $i_ran = true; });
259
260 $v = VenueCB::find(1);
261 $ret = $v->delete();
262
263 $this->assert_false($i_ran);
264 $this->assert_false($ret);
265 $this->assert_true(strpos(ActiveRecord\Table::load('VenueCB')->last_sql, 'DELETE') === false);
266 }
267
268 public function test_before_validation_returned_false_halts_execution()
269 {
270 VenueCB::$before_validation = array('before_validation_halt_execution');
271 ActiveRecord\Table::clear_cache('VenueCB');
272 $table = ActiveRecord\Table::load('VenueCB');
273
274 $v = VenueCB::find(1);
275 $v->name .= 'test';
276 $ret = $v->save();
277
278 $this->assert_false($ret);
279 $this->assert_true(strpos(ActiveRecord\Table::load('VenueCB')->last_sql, 'UPDATE') === false);
280 }
281};
282?>