Merge branch 'MDL-61480-master' of git://github.com/andrewnicols/moodle
[moodle.git] / lib / tests / persistent_test.php
blob9446e2a5aec83b11c448414df218cc0c1a199322
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Persistent class tests.
20 * @package core
21 * @copyright 2015 Frédéric Massart - FMCorz.net
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
26 global $CFG;
28 /**
29 * Persistent testcase.
31 * @package core
32 * @copyright 2015 Frédéric Massart - FMCorz.net
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 class core_persistent_testcase extends advanced_testcase {
37 public function setUp() {
38 $this->make_persistent_table();
39 $this->resetAfterTest();
42 /**
43 * Make the table for the persistent.
45 protected function make_persistent_table() {
46 global $DB;
47 $dbman = $DB->get_manager();
49 $table = new xmldb_table(core_testable_persistent::TABLE);
50 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
51 $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
52 $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
53 $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
54 $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
55 $table->add_field('parentid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
56 $table->add_field('path', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
57 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
58 $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
59 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
60 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
61 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
63 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
65 if ($dbman->table_exists($table)) {
66 $dbman->drop_table($table);
69 $dbman->create_table($table);
72 public function test_properties_definition() {
73 $expected = array(
74 'shortname' => array(
75 'type' => PARAM_TEXT,
76 'default' => '',
77 'null' => NULL_NOT_ALLOWED
79 'idnumber' => array(
80 'type' => PARAM_TEXT,
81 'null' => NULL_NOT_ALLOWED
83 'description' => array(
84 'type' => PARAM_TEXT,
85 'default' => '',
86 'null' => NULL_NOT_ALLOWED
88 'descriptionformat' => array(
89 'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN),
90 'type' => PARAM_INT,
91 'default' => FORMAT_HTML,
92 'null' => NULL_NOT_ALLOWED
94 'parentid' => array(
95 'type' => PARAM_INT,
96 'default' => 0,
97 'null' => NULL_NOT_ALLOWED
99 'path' => array(
100 'type' => PARAM_RAW,
101 'default' => '',
102 'null' => NULL_NOT_ALLOWED
104 'sortorder' => array(
105 'type' => PARAM_INT,
106 'message' => new lang_string('invalidrequest', 'error'),
107 'null' => NULL_NOT_ALLOWED
109 'scaleid' => array(
110 'default' => null,
111 'type' => PARAM_INT,
112 'null' => NULL_ALLOWED
114 'id' => array(
115 'default' => 0,
116 'type' => PARAM_INT,
117 'null' => NULL_NOT_ALLOWED
119 'timecreated' => array(
120 'default' => 0,
121 'type' => PARAM_INT,
122 'null' => NULL_NOT_ALLOWED
124 'timemodified' => array(
125 'default' => 0,
126 'type' => PARAM_INT,
127 'null' => NULL_NOT_ALLOWED
129 'usermodified' => array(
130 'default' => 0,
131 'type' => PARAM_INT,
132 'null' => NULL_NOT_ALLOWED
135 $this->assertEquals($expected, core_testable_persistent::properties_definition());
138 public function test_to_record() {
139 $p = new core_testable_persistent();
140 $expected = (object) array(
141 'shortname' => '',
142 'idnumber' => null,
143 'description' => '',
144 'descriptionformat' => FORMAT_HTML,
145 'parentid' => 0,
146 'path' => '',
147 'sortorder' => null,
148 'id' => 0,
149 'timecreated' => 0,
150 'timemodified' => 0,
151 'usermodified' => 0,
152 'scaleid' => null,
154 $this->assertEquals($expected, $p->to_record());
157 public function test_from_record() {
158 $p = new core_testable_persistent();
159 $data = (object) array(
160 'shortname' => 'ddd',
161 'idnumber' => 'abc',
162 'description' => 'xyz',
163 'descriptionformat' => FORMAT_PLAIN,
164 'parentid' => 999,
165 'path' => '/a/b/c',
166 'sortorder' => 12,
167 'id' => 1,
168 'timecreated' => 2,
169 'timemodified' => 3,
170 'usermodified' => 4,
171 'scaleid' => null,
173 $p->from_record($data);
174 $this->assertEquals($data, $p->to_record());
178 * @expectedException coding_exception
180 public function test_from_record_invalid_param() {
181 $p = new core_testable_persistent();
182 $data = (object) array(
183 'invalidparam' => 'abc'
186 $p->from_record($data);
189 public function test_validate() {
190 $data = (object) array(
191 'idnumber' => 'abc',
192 'sortorder' => 0
194 $p = new core_testable_persistent(0, $data);
195 $this->assertFalse(isset($p->beforevalidate));
196 $this->assertTrue($p->validate());
197 $this->assertTrue(isset($p->beforevalidate));
198 $this->assertTrue($p->is_valid());
199 $this->assertEquals(array(), $p->get_errors());
200 $p->set('descriptionformat', -100);
202 $expected = array(
203 'descriptionformat' => new lang_string('invaliddata', 'error'),
205 $this->assertEquals($expected, $p->validate());
206 $this->assertFalse($p->is_valid());
207 $this->assertEquals($expected, $p->get_errors());
210 public function test_validation_required() {
211 $data = (object) array(
212 'idnumber' => 'abc'
214 $p = new core_testable_persistent(0, $data);
215 $expected = array(
216 'sortorder' => new lang_string('requiredelement', 'form'),
218 $this->assertFalse($p->is_valid());
219 $this->assertEquals($expected, $p->get_errors());
222 public function test_validation_custom() {
223 $data = (object) array(
224 'idnumber' => 'abc',
225 'sortorder' => 10,
227 $p = new core_testable_persistent(0, $data);
228 $expected = array(
229 'sortorder' => new lang_string('invalidkey', 'error'),
231 $this->assertFalse($p->is_valid());
232 $this->assertEquals($expected, $p->get_errors());
235 public function test_validation_custom_message() {
236 $data = (object) array(
237 'idnumber' => 'abc',
238 'sortorder' => 'abc',
240 $p = new core_testable_persistent(0, $data);
241 $expected = array(
242 'sortorder' => new lang_string('invalidrequest', 'error'),
244 $this->assertFalse($p->is_valid());
245 $this->assertEquals($expected, $p->get_errors());
248 public function test_validation_choices() {
249 $data = (object) array(
250 'idnumber' => 'abc',
251 'sortorder' => 0,
252 'descriptionformat' => -100
254 $p = new core_testable_persistent(0, $data);
255 $expected = array(
256 'descriptionformat' => new lang_string('invaliddata', 'error'),
258 $this->assertFalse($p->is_valid());
259 $this->assertEquals($expected, $p->get_errors());
262 public function test_validation_type() {
263 $data = (object) array(
264 'idnumber' => 'abc',
265 'sortorder' => 'NaN'
267 $p = new core_testable_persistent(0, $data);
268 $this->assertFalse($p->is_valid());
269 $this->assertArrayHasKey('sortorder', $p->get_errors());
272 public function test_validation_null() {
273 $data = (object) array(
274 'idnumber' => null,
275 'sortorder' => 0,
276 'scaleid' => 'bad!'
278 $p = new core_testable_persistent(0, $data);
279 $this->assertFalse($p->is_valid());
280 $this->assertArrayHasKey('idnumber', $p->get_errors());
281 $this->assertArrayHasKey('scaleid', $p->get_errors());
282 $p->set('idnumber', 'abc');
283 $this->assertFalse($p->is_valid());
284 $this->assertArrayNotHasKey('idnumber', $p->get_errors());
285 $this->assertArrayHasKey('scaleid', $p->get_errors());
286 $p->set('scaleid', null);
287 $this->assertTrue($p->is_valid());
288 $this->assertArrayNotHasKey('scaleid', $p->get_errors());
291 public function test_create() {
292 global $DB;
293 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
294 $this->assertFalse(isset($p->beforecreate));
295 $this->assertFalse(isset($p->aftercreate));
296 $p->create();
297 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST);
298 $expected = $p->to_record();
299 $this->assertTrue(isset($p->beforecreate));
300 $this->assertTrue(isset($p->aftercreate));
301 $this->assertEquals($expected->sortorder, $record->sortorder);
302 $this->assertEquals($expected->idnumber, $record->idnumber);
303 $this->assertEquals($expected->id, $record->id);
304 $this->assertTrue($p->is_valid()); // Should always be valid after a create.
307 public function test_update() {
308 global $DB;
309 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
310 $p->create();
311 $id = $p->get('id');
312 $p->set('sortorder', 456);
313 $p->from_record((object) array('idnumber' => 'def'));
314 $this->assertFalse(isset($p->beforeupdate));
315 $this->assertFalse(isset($p->afterupdate));
316 $p->update();
318 $expected = $p->to_record();
319 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST);
320 $this->assertTrue(isset($p->beforeupdate));
321 $this->assertTrue(isset($p->afterupdate));
322 $this->assertEquals($id, $record->id);
323 $this->assertEquals(456, $record->sortorder);
324 $this->assertEquals('def', $record->idnumber);
325 $this->assertTrue($p->is_valid()); // Should always be valid after an update.
328 public function test_save() {
329 global $DB;
330 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
331 $this->assertFalse(isset($p->beforecreate));
332 $this->assertFalse(isset($p->aftercreate));
333 $this->assertFalse(isset($p->beforeupdate));
334 $this->assertFalse(isset($p->beforeupdate));
335 $p->save();
336 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST);
337 $expected = $p->to_record();
338 $this->assertTrue(isset($p->beforecreate));
339 $this->assertTrue(isset($p->aftercreate));
340 $this->assertFalse(isset($p->beforeupdate));
341 $this->assertFalse(isset($p->beforeupdate));
342 $this->assertEquals($expected->sortorder, $record->sortorder);
343 $this->assertEquals($expected->idnumber, $record->idnumber);
344 $this->assertEquals($expected->id, $record->id);
345 $this->assertTrue($p->is_valid()); // Should always be valid after a save/create.
347 $p->set('idnumber', 'abcd');
348 $p->save();
349 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST);
350 $expected = $p->to_record();
351 $this->assertTrue(isset($p->beforeupdate));
352 $this->assertTrue(isset($p->beforeupdate));
353 $this->assertEquals($expected->sortorder, $record->sortorder);
354 $this->assertEquals($expected->idnumber, $record->idnumber);
355 $this->assertEquals($expected->id, $record->id);
356 $this->assertTrue($p->is_valid()); // Should always be valid after a save/update.
359 public function test_read() {
360 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
361 $p->create();
362 unset($p->beforevalidate);
363 unset($p->beforecreate);
364 unset($p->aftercreate);
366 $p2 = new core_testable_persistent($p->get('id'));
367 $this->assertEquals($p, $p2);
369 $p3 = new core_testable_persistent();
370 $p3->set('id', $p->get('id'));
371 $p3->read();
372 $this->assertEquals($p, $p3);
375 public function test_delete() {
376 global $DB;
378 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
379 $p->create();
380 $this->assertNotEquals(0, $p->get('id'));
381 $this->assertTrue($DB->record_exists_select(core_testable_persistent::TABLE, 'id = ?', array($p->get('id'))));
382 $this->assertFalse(isset($p->beforedelete));
383 $this->assertFalse(isset($p->afterdelete));
385 $p->delete();
386 $this->assertFalse($DB->record_exists_select(core_testable_persistent::TABLE, 'id = ?', array($p->get('id'))));
387 $this->assertEquals(0, $p->get('id'));
388 $this->assertEquals(true, $p->beforedelete);
389 $this->assertEquals(true, $p->afterdelete);
392 public function test_has_property() {
393 $this->assertFalse(core_testable_persistent::has_property('unknown'));
394 $this->assertTrue(core_testable_persistent::has_property('idnumber'));
397 public function test_custom_setter_getter() {
398 global $DB;
400 $path = array(1, 2, 3);
401 $json = json_encode($path);
403 $p = new core_testable_persistent(0, (object) array('sortorder' => 0, 'idnumber' => 'abc'));
404 $p->set('path', $path);
405 $this->assertEquals($path, $p->get('path'));
406 $this->assertEquals($json, $p->to_record()->path);
408 $p->create();
409 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), 'id, path', MUST_EXIST);
410 $this->assertEquals($json, $record->path);
413 public function test_record_exists() {
414 global $DB;
415 $this->assertFalse($DB->record_exists(core_testable_persistent::TABLE, array('idnumber' => 'abc')));
416 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc'));
417 $p->create();
418 $id = $p->get('id');
419 $this->assertTrue(core_testable_persistent::record_exists($id));
420 $this->assertTrue($DB->record_exists(core_testable_persistent::TABLE, array('idnumber' => 'abc')));
421 $p->delete();
422 $this->assertFalse(core_testable_persistent::record_exists($id));
425 public function test_get_sql_fields() {
426 $expected = '' .
427 'c.id AS prefix_id, ' .
428 'c.shortname AS prefix_shortname, ' .
429 'c.idnumber AS prefix_idnumber, ' .
430 'c.description AS prefix_description, ' .
431 'c.descriptionformat AS prefix_descriptionformat, ' .
432 'c.parentid AS prefix_parentid, ' .
433 'c.path AS prefix_path, ' .
434 'c.sortorder AS prefix_sortorder, ' .
435 'c.scaleid AS prefix_scaleid, ' .
436 'c.timecreated AS prefix_timecreated, ' .
437 'c.timemodified AS prefix_timemodified, ' .
438 'c.usermodified AS prefix_usermodified';
439 $this->assertEquals($expected, core_testable_persistent::get_sql_fields('c', 'prefix_'));
443 * @expectedException coding_exception
444 * @expectedExceptionMessageRegExp /The alias .+ exceeds 30 characters/
446 public function test_get_sql_fields_too_long() {
447 core_testable_persistent::get_sql_fields('c');
452 * Example persistent class.
454 * @package core
455 * @copyright 2015 Frédéric Massart - FMCorz.net
456 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
458 class core_testable_persistent extends \core\persistent {
460 const TABLE = 'phpunit_persistent';
462 protected static function define_properties() {
463 return array(
464 'shortname' => array(
465 'type' => PARAM_TEXT,
466 'default' => ''
468 'idnumber' => array(
469 'type' => PARAM_TEXT,
471 'description' => array(
472 'type' => PARAM_TEXT,
473 'default' => ''
475 'descriptionformat' => array(
476 'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN),
477 'type' => PARAM_INT,
478 'default' => FORMAT_HTML
480 'parentid' => array(
481 'type' => PARAM_INT,
482 'default' => 0
484 'path' => array(
485 'type' => PARAM_RAW,
486 'default' => ''
488 'sortorder' => array(
489 'type' => PARAM_INT,
490 'message' => new lang_string('invalidrequest', 'error')
492 'scaleid' => array(
493 'type' => PARAM_INT,
494 'default' => null,
495 'null' => NULL_ALLOWED
500 protected function before_validate() {
501 $this->beforevalidate = true;
504 protected function before_create() {
505 $this->beforecreate = true;
508 protected function before_update() {
509 $this->beforeupdate = true;
512 protected function before_delete() {
513 $this->beforedelete = true;
516 protected function after_create() {
517 $this->aftercreate = true;
520 protected function after_update($result) {
521 $this->afterupdate = true;
524 protected function after_delete($result) {
525 $this->afterdelete = true;
528 protected function get_path() {
529 $value = $this->raw_get('path');
530 if (!empty($value)) {
531 $value = json_decode($value);
533 return $value;
536 protected function set_path($value) {
537 if (!empty($value)) {
538 $value = json_encode($value);
540 $this->raw_set('path', $value);
543 protected function validate_sortorder($value) {
544 if ($value == 10) {
545 return new lang_string('invalidkey', 'error');
547 return true;