a tiny mvc framework for php using php-activerecord
1<?php
2include 'helpers/config.php';
3
4class ActiveRecordTest extends DatabaseTest
5{
6 public function set_up($connection_name=null)
7 {
8 parent::set_up($connection_name);
9 $this->options = array('conditions' => 'blah', 'order' => 'blah');
10 }
11
12 public function test_options_is_not()
13 {
14 $this->assert_false(Author::is_options_hash(null));
15 $this->assert_false(Author::is_options_hash(''));
16 $this->assert_false(Author::is_options_hash('tito'));
17 $this->assert_false(Author::is_options_hash(array()));
18 $this->assert_false(Author::is_options_hash(array(1,2,3)));
19 }
20
21 /**
22 * @expectedException ActiveRecord\ActiveRecordException
23 */
24 public function test_options_hash_with_unknown_keys() {
25 $this->assert_false(Author::is_options_hash(array('conditions' => 'blah', 'sharks' => 'laserz', 'dubya' => 'bush')));
26 }
27
28 public function test_options_is_hash()
29 {
30 $this->assert_true(Author::is_options_hash($this->options));
31 }
32
33 public function test_extract_and_validate_options() {
34 $args = array('first',$this->options);
35 $this->assert_equals($this->options,Author::extract_and_validate_options($args));
36 $this->assert_equals(array('first'),$args);
37 }
38
39 public function test_extract_and_validate_options_with_array_in_args() {
40 $args = array('first',array(1,2),$this->options);
41 $this->assert_equals($this->options,Author::extract_and_validate_options($args));
42 }
43
44 public function test_extract_and_validate_options_removes_options_hash() {
45 $args = array('first',$this->options);
46 Author::extract_and_validate_options($args);
47 $this->assert_equals(array('first'),$args);
48 }
49
50 public function test_extract_and_validate_options_nope() {
51 $args = array('first');
52 $this->assert_equals(array(),Author::extract_and_validate_options($args));
53 $this->assert_equals(array('first'),$args);
54 }
55
56 public function test_extract_and_validate_options_nope_because_wasnt_at_end() {
57 $args = array('first',$this->options,array(1,2));
58 $this->assert_equals(array(),Author::extract_and_validate_options($args));
59 }
60
61 /**
62 * @expectedException ActiveRecord\UndefinedPropertyException
63 */
64 public function test_invalid_attribute()
65 {
66 $author = Author::find('first',array('conditions' => 'author_id=1'));
67 $author->some_invalid_field_name;
68 }
69
70 public function test_invalid_attributes()
71 {
72 $book = Book::find(1);
73 try {
74 $book->update_attributes(array('name' => 'new name', 'invalid_attribute' => true , 'another_invalid_attribute' => 'something'));
75 } catch (ActiveRecord\UndefinedPropertyException $e) {
76 $exceptions = explode("\r\n", $e->getMessage());
77 }
78
79 $this->assert_equals(1, substr_count($exceptions[0], 'invalid_attribute'));
80 $this->assert_equals(1, substr_count($exceptions[1], 'another_invalid_attribute'));
81 }
82
83 public function test_getter_undefined_property_exception_includes_model_name()
84 {
85 $this->assert_exception_message_contains("Author->this_better_not_exist",function()
86 {
87 $author = new Author();
88 $author->this_better_not_exist;
89 });
90 }
91
92 public function test_mass_assignment_undefined_property_exception_includes_model_name()
93 {
94 $this->assert_exception_message_contains("Author->this_better_not_exist",function()
95 {
96 new Author(array("this_better_not_exist" => "hi"));
97 });
98 }
99
100 public function test_setter_undefined_property_exception_includes_model_name()
101 {
102 $this->assert_exception_message_contains("Author->this_better_not_exist",function()
103 {
104 $author = new Author();
105 $author->this_better_not_exist = "hi";
106 });
107 }
108
109 public function test_get_values_for()
110 {
111 $book = Book::find_by_name('Ancient Art of Main Tanking');
112 $ret = $book->get_values_for(array('book_id','author_id'));
113 $this->assert_equals(array('book_id','author_id'),array_keys($ret));
114 $this->assert_equals(array(1,1),array_values($ret));
115 }
116
117 public function test_hyphenated_column_names_to_underscore()
118 {
119 if ($this->conn instanceof ActiveRecord\OciAdapter)
120 return;
121
122 $keys = array_keys(RmBldg::first()->attributes());
123 $this->assert_true(in_array('rm_name',$keys));
124 }
125
126 public function test_column_names_with_spaces()
127 {
128 if ($this->conn instanceof ActiveRecord\OciAdapter)
129 return;
130
131 $keys = array_keys(RmBldg::first()->attributes());
132 $this->assert_true(in_array('space_out',$keys));
133 }
134
135 public function test_mixed_case_column_name()
136 {
137 $keys = array_keys(Author::first()->attributes());
138 $this->assert_true(in_array('mixedcasefield',$keys));
139 }
140
141 public function test_mixed_case_primary_key_save()
142 {
143 $venue = Venue::find(1);
144 $venue->name = 'should not throw exception';
145 $venue->save();
146 $this->assert_equals($venue->name,Venue::find(1)->name);
147 }
148
149 public function test_reload()
150 {
151 $venue = Venue::find(1);
152 $this->assert_equals('NY', $venue->state);
153 $venue->state = 'VA';
154 $this->assert_equals('VA', $venue->state);
155 $venue->reload();
156 $this->assert_equals('NY', $venue->state);
157 }
158
159 public function test_reload_protected_attribute()
160 {
161 $book = BookAttrAccessible::find(1);
162
163 $book->name = "Should not stay";
164 $book->reload();
165 $this->assert_not_equals("Should not stay", $book->name);
166 }
167
168 public function test_active_record_model_home_not_set()
169 {
170 $home = ActiveRecord\Config::instance()->get_model_directory();
171 ActiveRecord\Config::instance()->set_model_directory(__FILE__);
172 $this->assert_equals(false,class_exists('TestAutoload'));
173
174 ActiveRecord\Config::instance()->set_model_directory($home);
175 }
176
177 public function test_auto_load_with_namespaced_model()
178 {
179 $this->assert_true(class_exists('NamespaceTest\Book'));
180 }
181
182 public function test_namespace_gets_stripped_from_table_name()
183 {
184 $model = new NamespaceTest\Book();
185 $this->assert_equals('books',$model->table()->table);
186 }
187
188 public function test_namespace_gets_stripped_from_inferred_foreign_key()
189 {
190 $model = new NamespaceTest\Book();
191 $table = ActiveRecord\Table::load(get_class($model));
192 $this->assert_equals($table->get_relationship('parent_book')->foreign_key[0], 'book_id');
193 }
194
195 public function test_should_have_all_column_attributes_when_initializing_with_array()
196 {
197 $author = new Author(array('name' => 'Tito'));
198 $this->assert_true(count(array_keys($author->attributes())) >= 9);
199 }
200
201 public function test_defaults()
202 {
203 $author = new Author();
204 $this->assert_equals('default_name',$author->name);
205 }
206
207 public function test_alias_attribute_getter()
208 {
209 $venue = Venue::find(1);
210 $this->assert_equals($venue->marquee, $venue->name);
211 $this->assert_equals($venue->mycity, $venue->city);
212 }
213
214 public function test_alias_attribute_setter()
215 {
216 $venue = Venue::find(1);
217 $venue->marquee = 'new name';
218 $this->assert_equals($venue->marquee, 'new name');
219 $this->assert_equals($venue->marquee, $venue->name);
220
221 $venue->name = 'another name';
222 $this->assert_equals($venue->name, 'another name');
223 $this->assert_equals($venue->marquee, $venue->name);
224 }
225
226 public function test_alias_from_mass_attributes()
227 {
228 $venue = new Venue(array('marquee' => 'meme', 'id' => 123));
229 $this->assert_equals('meme',$venue->name);
230 $this->assert_equals($venue->marquee,$venue->name);
231 }
232
233 public function test_gh18_isset_on_aliased_attribute()
234 {
235 $this->assert_true(isset(Venue::first()->marquee));
236 }
237
238 public function test_attr_accessible()
239 {
240 $book = new BookAttrAccessible(array('name' => 'should not be set', 'author_id' => 1));
241 $this->assert_null($book->name);
242 $this->assert_equals(1,$book->author_id);
243 $book->name = 'test';
244 $this->assert_equals('test', $book->name);
245 }
246
247 public function test_attr_protected()
248 {
249 $book = new BookAttrAccessible(array('book_id' => 999));
250 $this->assert_null($book->book_id);
251 $book->book_id = 999;
252 $this->assert_equals(999, $book->book_id);
253 }
254
255 public function test_isset()
256 {
257 $book = new Book();
258 $this->assert_true(isset($book->name));
259 $this->assert_false(isset($book->sharks));
260 }
261
262 public function test_readonly_only_halt_on_write_method()
263 {
264 $book = Book::first(array('readonly' => true));
265 $this->assert_true($book->is_readonly());
266
267 try {
268 $book->save();
269 $this-fail('expected exception ActiveRecord\ReadonlyException');
270 } catch (ActiveRecord\ReadonlyException $e) {
271 }
272
273 $book->name = 'some new name';
274 $this->assert_equals($book->name, 'some new name');
275 }
276
277 public function test_cast_when_using_setter()
278 {
279 $book = new Book();
280 $book->book_id = '1';
281 $this->assert_same(1,$book->book_id);
282 }
283
284 public function test_cast_when_loading()
285 {
286 $book = Book::find(1);
287 $this->assert_same(1,$book->book_id);
288 $this->assert_same('Ancient Art of Main Tanking',$book->name);
289 }
290
291 public function test_cast_defaults()
292 {
293 $book = new Book();
294 $this->assert_same(0.0,$book->special);
295 }
296
297 public function test_transaction_committed()
298 {
299 $original = Author::count();
300 $ret = Author::transaction(function() { Author::create(array("name" => "blah")); });
301 $this->assert_equals($original+1,Author::count());
302 $this->assert_true($ret);
303 }
304
305 public function test_transaction_committed_when_returning_true()
306 {
307 $original = Author::count();
308 $ret = Author::transaction(function() { Author::create(array("name" => "blah")); return true; });
309 $this->assert_equals($original+1,Author::count());
310 $this->assert_true($ret);
311 }
312
313 public function test_transaction_rolledback_by_returning_false()
314 {
315 $original = Author::count();
316
317 $ret = Author::transaction(function()
318 {
319 Author::create(array("name" => "blah"));
320 return false;
321 });
322
323 $this->assert_equals($original,Author::count());
324 $this->assert_false($ret);
325 }
326
327 public function test_transaction_rolledback_by_throwing_exception()
328 {
329 $original = Author::count();
330 $exception = null;
331
332 try
333 {
334 Author::transaction(function()
335 {
336 Author::create(array("name" => "blah"));
337 throw new Exception("blah");
338 });
339 }
340 catch (Exception $e)
341 {
342 $exception = $e;
343 }
344
345 $this->assert_not_null($exception);
346 $this->assert_equals($original,Author::count());
347 }
348
349 public function test_delegate()
350 {
351 $event = Event::first();
352 $this->assert_equals($event->venue->state,$event->state);
353 $this->assert_equals($event->venue->address,$event->address);
354 }
355
356 public function test_delegate_prefix()
357 {
358 $event = Event::first();
359 $this->assert_equals($event->host->name,$event->woot_name);
360 }
361
362 public function test_delegate_returns_null_if_relationship_does_not_exist()
363 {
364 $event = new Event();
365 $this->assert_null($event->state);
366 }
367
368 public function test_delegate_set_attribute()
369 {
370 $event = Event::first();
371 $event->state = 'MEXICO';
372 $this->assert_equals('MEXICO',$event->venue->state);
373 }
374
375 public function test_delegate_getter_gh_98()
376 {
377 Venue::$use_custom_get_state_getter = true;
378
379 $event = Event::first();
380 $this->assert_equals('ny', $event->venue->state);
381 $this->assert_equals('ny', $event->state);
382
383 Venue::$use_custom_get_state_getter = false;
384 }
385
386 public function test_delegate_setter_gh_98()
387 {
388 Venue::$use_custom_set_state_setter = true;
389
390 $event = Event::first();
391 $event->state = 'MEXICO';
392 $this->assert_equals('MEXICO#',$event->venue->state);
393
394 Venue::$use_custom_set_state_setter = false;
395 }
396
397 public function test_table_name_with_underscores()
398 {
399 $this->assert_not_null(AwesomePerson::first());
400 }
401
402 public function test_model_should_default_as_new_record()
403 {
404 $author = new Author();
405 $this->assert_true($author->is_new_record());
406 }
407
408 public function test_setter()
409 {
410 $author = new Author();
411 $author->password = 'plaintext';
412 $this->assert_equals(md5('plaintext'),$author->encrypted_password);
413 }
414
415 public function test_setter_with_same_name_as_an_attribute()
416 {
417 $author = new Author();
418 $author->name = 'bob';
419 $this->assert_equals('BOB',$author->name);
420 }
421
422 public function test_getter()
423 {
424 $book = Book::first();
425 $this->assert_equals(strtoupper($book->name), $book->upper_name);
426 }
427
428 public function test_getter_with_same_name_as_an_attribute()
429 {
430 Book::$use_custom_get_name_getter = true;
431 $book = new Book;
432 $book->name = 'bob';
433 $this->assert_equals('BOB', $book->name);
434 Book::$use_custom_get_name_getter = false;
435 }
436
437 public function test_setting_invalid_date_should_set_date_to_null()
438 {
439 $author = new Author();
440 $author->created_at = 'CURRENT_TIMESTAMP';
441 $this->assertNull($author->created_at);
442 }
443
444 public function test_table_name()
445 {
446 $this->assert_equals('authors',Author::table_name());
447 }
448
449 /**
450 * @expectedException ActiveRecord\ActiveRecordException
451 */
452 public function test_undefined_instance_method()
453 {
454 Author::first()->find_by_name('sdf');
455 }
456
457 public function test_clear_cache_for_specific_class()
458 {
459 $book_table1 = ActiveRecord\Table::load('Book');
460 $book_table2 = ActiveRecord\Table::load('Book');
461 ActiveRecord\Table::clear_cache('Book');
462 $book_table3 = ActiveRecord\Table::load('Book');
463
464 $this->assert_true($book_table1 === $book_table2);
465 $this->assert_true($book_table1 !== $book_table3);
466 }
467
468 public function test_flag_dirty()
469 {
470 $author = new Author();
471 $author->flag_dirty('some_date');
472 $this->assert_has_keys('some_date', $author->dirty_attributes());
473 $this->assert_true($author->attribute_is_dirty('some_date'));
474 $author->save();
475 $this->assert_false($author->attribute_is_dirty('some_date'));
476 }
477
478 public function test_flag_dirty_attribute()
479 {
480 $author = new Author();
481 $author->flag_dirty('some_inexistant_property');
482 $this->assert_null($author->dirty_attributes());
483 $this->assert_false($author->attribute_is_dirty('some_inexistant_property'));
484 }
485
486 public function test_assigning_php_datetime_gets_converted_to_ar_datetime()
487 {
488 $author = new Author();
489 $author->created_at = $now = new \DateTime();
490 $this->assert_is_a("ActiveRecord\\DateTime",$author->created_at);
491 $this->assert_datetime_equals($now,$author->created_at);
492 }
493
494 public function test_assigning_from_mass_assignment_php_datetime_gets_converted_to_ar_datetime()
495 {
496 $author = new Author(array('created_at' => new \DateTime()));
497 $this->assert_is_a("ActiveRecord\\DateTime",$author->created_at);
498 }
499
500 public function test_get_real_attribute_name()
501 {
502 $venue = new Venue();
503 $this->assert_equals('name', $venue->get_real_attribute_name('name'));
504 $this->assert_equals('name', $venue->get_real_attribute_name('marquee'));
505 $this->assert_equals(null, $venue->get_real_attribute_name('invalid_field'));
506 }
507
508 public function test_id_setter_works_with_table_without_pk_named_attribute()
509 {
510 $author = new Author(array('id' => 123));
511 $this->assert_equals(123,$author->author_id);
512 }
513
514 public function test_query()
515 {
516 $row = Author::query('SELECT COUNT(*) AS n FROM authors',null)->fetch();
517 $this->assert_true($row['n'] > 1);
518
519 $row = Author::query('SELECT COUNT(*) AS n FROM authors WHERE name=?',array('Tito'))->fetch();
520 $this->assert_equals(array('n' => 1), $row);
521 }
522};
523?>