See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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. 13 // 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/>. 16 17 /** 18 * Persistent class tests. 19 * 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 23 */ 24 25 namespace core; 26 27 use advanced_testcase; 28 use coding_exception; 29 use dml_missing_record_exception; 30 use lang_string; 31 use xmldb_table; 32 33 defined('MOODLE_INTERNAL') || die(); 34 35 /** 36 * Persistent testcase. 37 * 38 * @package core 39 * @copyright 2015 Frédéric Massart - FMCorz.net 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 * @covers \core\persistent 42 */ 43 class persistent_test extends advanced_testcase { 44 45 public function setUp(): void { 46 $this->make_persistent_table(); 47 $this->make_second_persistent_table(); 48 $this->resetAfterTest(); 49 } 50 51 /** 52 * Make the table for the persistent. 53 */ 54 protected function make_persistent_table() { 55 global $DB; 56 $dbman = $DB->get_manager(); 57 58 $table = new xmldb_table(core_testable_persistent::TABLE); 59 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 60 $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null); 61 $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null); 62 $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null); 63 $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0'); 64 $table->add_field('parentid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 65 $table->add_field('path', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); 66 $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 67 $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 68 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 69 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 70 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 71 72 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); 73 74 if ($dbman->table_exists($table)) { 75 $dbman->drop_table($table); 76 } 77 78 $dbman->create_table($table); 79 } 80 81 /** 82 * Make the second table for the persistent. 83 */ 84 protected function make_second_persistent_table() { 85 global $DB; 86 $dbman = $DB->get_manager(); 87 88 $table = new xmldb_table(core_testable_second_persistent::TABLE); 89 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 90 $table->add_field('someint', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 91 $table->add_field('intnull', XMLDB_TYPE_INTEGER, '10', null, null, null, null); 92 $table->add_field('somefloat', XMLDB_TYPE_FLOAT, '10,5', null, null, null, null); 93 $table->add_field('sometext', XMLDB_TYPE_TEXT, null, null, null, null, null); 94 $table->add_field('someraw', XMLDB_TYPE_CHAR, '100', null, null, null, null); 95 $table->add_field('booltrue', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0'); 96 $table->add_field('boolfalse', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0'); 97 $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 98 $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); 99 $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); 100 101 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); 102 103 if ($dbman->table_exists($table)) { 104 $dbman->drop_table($table); 105 } 106 107 $dbman->create_table($table); 108 } 109 110 public function test_properties_definition() { 111 $expected = array( 112 'shortname' => array( 113 'type' => PARAM_TEXT, 114 'default' => '', 115 'null' => NULL_NOT_ALLOWED 116 ), 117 'idnumber' => array( 118 'type' => PARAM_TEXT, 119 'null' => NULL_NOT_ALLOWED 120 ), 121 'description' => array( 122 'type' => PARAM_TEXT, 123 'default' => '', 124 'null' => NULL_NOT_ALLOWED 125 ), 126 'descriptionformat' => array( 127 'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN), 128 'type' => PARAM_INT, 129 'default' => FORMAT_HTML, 130 'null' => NULL_NOT_ALLOWED 131 ), 132 'parentid' => array( 133 'type' => PARAM_INT, 134 'default' => 0, 135 'null' => NULL_NOT_ALLOWED 136 ), 137 'path' => array( 138 'type' => PARAM_RAW, 139 'default' => '', 140 'null' => NULL_NOT_ALLOWED 141 ), 142 'sortorder' => array( 143 'type' => PARAM_INT, 144 'message' => new lang_string('invalidrequest', 'error'), 145 'null' => NULL_NOT_ALLOWED 146 ), 147 'scaleid' => array( 148 'default' => null, 149 'type' => PARAM_INT, 150 'null' => NULL_ALLOWED 151 ), 152 'id' => array( 153 'default' => 0, 154 'type' => PARAM_INT, 155 'null' => NULL_NOT_ALLOWED 156 ), 157 'timecreated' => array( 158 'default' => 0, 159 'type' => PARAM_INT, 160 'null' => NULL_NOT_ALLOWED 161 ), 162 'timemodified' => array( 163 'default' => 0, 164 'type' => PARAM_INT, 165 'null' => NULL_NOT_ALLOWED 166 ), 167 'usermodified' => array( 168 'default' => 0, 169 'type' => PARAM_INT, 170 'null' => NULL_NOT_ALLOWED 171 ), 172 ); 173 $this->assertEquals($expected, core_testable_persistent::properties_definition()); 174 } 175 176 /** 177 * Test creating persistent instance by specifying record ID in constructor 178 */ 179 public function test_constructor() : void { 180 $persistent = (new core_testable_persistent(0, (object) [ 181 'idnumber' => '123', 182 'sortorder' => 1, 183 ]))->create(); 184 185 // Now create a new instance, passing the original instance ID in the constructor. 186 $another = new core_testable_persistent($persistent->get('id')); 187 $this->assertEquals($another->to_record(), $persistent->to_record()); 188 } 189 190 /** 191 * Test creating persistent instance by specifying non-existing record ID in constructor throws appropriate exception 192 */ 193 public function test_constructor_invalid(): void { 194 $this->expectException(dml_missing_record_exception::class); 195 $this->expectExceptionMessage('Can\'t find data record in database table phpunit_persistent.'); 196 new core_testable_persistent(42); 197 } 198 199 public function test_to_record() { 200 $p = new core_testable_persistent(); 201 $expected = (object) array( 202 'shortname' => '', 203 'idnumber' => null, 204 'description' => '', 205 'descriptionformat' => FORMAT_HTML, 206 'parentid' => 0, 207 'path' => '', 208 'sortorder' => null, 209 'id' => 0, 210 'timecreated' => 0, 211 'timemodified' => 0, 212 'usermodified' => 0, 213 'scaleid' => null, 214 ); 215 $this->assertEquals($expected, $p->to_record()); 216 } 217 218 public function test_from_record() { 219 $p = new core_testable_persistent(); 220 $data = (object) array( 221 'shortname' => 'ddd', 222 'idnumber' => 'abc', 223 'description' => 'xyz', 224 'descriptionformat' => FORMAT_PLAIN, 225 'parentid' => 999, 226 'path' => '/a/b/c', 227 'sortorder' => 12, 228 'id' => 1, 229 'timecreated' => 2, 230 'timemodified' => 3, 231 'usermodified' => 4, 232 'scaleid' => null, 233 ); 234 $p->from_record($data); 235 $this->assertEquals($data, $p->to_record()); 236 } 237 238 public function test_from_record_invalid_param() { 239 $p = new core_testable_persistent(); 240 $data = (object) array( 241 'shortname' => 'ddd', 242 'idnumber' => 'abc', 243 'description' => 'xyz', 244 'descriptionformat' => FORMAT_PLAIN, 245 'parentid' => 999, 246 'path' => '/a/b/c', 247 'sortorder' => 12, 248 'id' => 1, 249 'timecreated' => 2, 250 'timemodified' => 3, 251 'usermodified' => 4, 252 'scaleid' => null, 253 'invalidparam' => 'abc' 254 ); 255 256 $p->from_record($data); 257 258 // Previous call should succeed, assert we get back all data except invalid param. 259 unset($data->invalidparam); 260 $this->assertEquals($data, $p->to_record()); 261 } 262 263 public function test_validate() { 264 $data = (object) array( 265 'idnumber' => 'abc', 266 'sortorder' => 0 267 ); 268 $p = new core_testable_persistent(0, $data); 269 $this->assertFalse(isset($p->beforevalidate)); 270 $this->assertTrue($p->validate()); 271 $this->assertTrue(isset($p->beforevalidate)); 272 $this->assertTrue($p->is_valid()); 273 $this->assertEquals(array(), $p->get_errors()); 274 $p->set('descriptionformat', -100); 275 276 $expected = array( 277 'descriptionformat' => new lang_string('invaliddata', 'error'), 278 ); 279 $this->assertEquals($expected, $p->validate()); 280 $this->assertFalse($p->is_valid()); 281 $this->assertEquals($expected, $p->get_errors()); 282 } 283 284 public function test_validation_required() { 285 $data = (object) array( 286 'idnumber' => 'abc' 287 ); 288 $p = new core_testable_persistent(0, $data); 289 $expected = array( 290 'sortorder' => new lang_string('requiredelement', 'form'), 291 ); 292 $this->assertFalse($p->is_valid()); 293 $this->assertEquals($expected, $p->get_errors()); 294 } 295 296 public function test_validation_custom() { 297 $data = (object) array( 298 'idnumber' => 'abc', 299 'sortorder' => 10, 300 ); 301 $p = new core_testable_persistent(0, $data); 302 $expected = array( 303 'sortorder' => new lang_string('invalidkey', 'error'), 304 ); 305 $this->assertFalse($p->is_valid()); 306 $this->assertEquals($expected, $p->get_errors()); 307 } 308 309 public function test_validation_custom_message() { 310 $data = (object) array( 311 'idnumber' => 'abc', 312 'sortorder' => 'abc', 313 ); 314 $p = new core_testable_persistent(0, $data); 315 $expected = array( 316 'sortorder' => new lang_string('invalidrequest', 'error'), 317 ); 318 $this->assertFalse($p->is_valid()); 319 $this->assertEquals($expected, $p->get_errors()); 320 } 321 322 public function test_validation_choices() { 323 $data = (object) array( 324 'idnumber' => 'abc', 325 'sortorder' => 0, 326 'descriptionformat' => -100 327 ); 328 $p = new core_testable_persistent(0, $data); 329 $expected = array( 330 'descriptionformat' => new lang_string('invaliddata', 'error'), 331 ); 332 $this->assertFalse($p->is_valid()); 333 $this->assertEquals($expected, $p->get_errors()); 334 } 335 336 public function test_validation_type() { 337 $data = (object) array( 338 'idnumber' => 'abc', 339 'sortorder' => 'NaN' 340 ); 341 $p = new core_testable_persistent(0, $data); 342 $this->assertFalse($p->is_valid()); 343 $this->assertArrayHasKey('sortorder', $p->get_errors()); 344 } 345 346 public function test_validation_null() { 347 $data = (object) array( 348 'idnumber' => null, 349 'sortorder' => 0, 350 'scaleid' => 'bad!' 351 ); 352 $p = new core_testable_persistent(0, $data); 353 $this->assertFalse($p->is_valid()); 354 $this->assertArrayHasKey('idnumber', $p->get_errors()); 355 $this->assertArrayHasKey('scaleid', $p->get_errors()); 356 $p->set('idnumber', 'abc'); 357 $this->assertFalse($p->is_valid()); 358 $this->assertArrayNotHasKey('idnumber', $p->get_errors()); 359 $this->assertArrayHasKey('scaleid', $p->get_errors()); 360 $p->set('scaleid', null); 361 $this->assertTrue($p->is_valid()); 362 $this->assertArrayNotHasKey('scaleid', $p->get_errors()); 363 } 364 365 public function test_create() { 366 global $DB; 367 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 368 $this->assertFalse(isset($p->beforecreate)); 369 $this->assertFalse(isset($p->aftercreate)); 370 $p->create(); 371 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST); 372 $expected = $p->to_record(); 373 $this->assertTrue(isset($p->beforecreate)); 374 $this->assertTrue(isset($p->aftercreate)); 375 $this->assertEquals($expected->sortorder, $record->sortorder); 376 $this->assertEquals($expected->idnumber, $record->idnumber); 377 $this->assertEquals($expected->id, $record->id); 378 $this->assertTrue($p->is_valid()); // Should always be valid after a create. 379 } 380 381 public function test_update() { 382 global $DB; 383 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 384 $p->create(); 385 $id = $p->get('id'); 386 $p->set('sortorder', 456); 387 $p->from_record((object) array('idnumber' => 'def')); 388 $this->assertFalse(isset($p->beforeupdate)); 389 $this->assertFalse(isset($p->afterupdate)); 390 $p->update(); 391 392 $expected = $p->to_record(); 393 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST); 394 $this->assertTrue(isset($p->beforeupdate)); 395 $this->assertTrue(isset($p->afterupdate)); 396 $this->assertEquals($id, $record->id); 397 $this->assertEquals(456, $record->sortorder); 398 $this->assertEquals('def', $record->idnumber); 399 $this->assertTrue($p->is_valid()); // Should always be valid after an update. 400 } 401 402 /** 403 * Test set_many prior to updating the persistent 404 */ 405 public function test_set_many_update(): void { 406 global $DB; 407 408 $persistent = (new core_testable_persistent(0, (object) [ 409 'idnumber' => 'test', 410 'sortorder' => 2 411 ]))->create(); 412 413 // Set multiple properties, and update. 414 $persistent->set_many([ 415 'idnumber' => 'test2', 416 'sortorder' => 1, 417 ])->update(); 418 419 // Confirm our persistent was updated. 420 $record = $DB->get_record(core_testable_persistent::TABLE, ['id' => $persistent->get('id')], '*', MUST_EXIST); 421 $this->assertEquals('test2', $record->idnumber); 422 $this->assertEquals(1, $record->sortorder); 423 } 424 425 public function test_save() { 426 global $DB; 427 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 428 $this->assertFalse(isset($p->beforecreate)); 429 $this->assertFalse(isset($p->aftercreate)); 430 $this->assertFalse(isset($p->beforeupdate)); 431 $this->assertFalse(isset($p->beforeupdate)); 432 $p->save(); 433 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST); 434 $expected = $p->to_record(); 435 $this->assertTrue(isset($p->beforecreate)); 436 $this->assertTrue(isset($p->aftercreate)); 437 $this->assertFalse(isset($p->beforeupdate)); 438 $this->assertFalse(isset($p->beforeupdate)); 439 $this->assertEquals($expected->sortorder, $record->sortorder); 440 $this->assertEquals($expected->idnumber, $record->idnumber); 441 $this->assertEquals($expected->id, $record->id); 442 $this->assertTrue($p->is_valid()); // Should always be valid after a save/create. 443 444 $p->set('idnumber', 'abcd'); 445 $p->save(); 446 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), '*', MUST_EXIST); 447 $expected = $p->to_record(); 448 $this->assertTrue(isset($p->beforeupdate)); 449 $this->assertTrue(isset($p->beforeupdate)); 450 $this->assertEquals($expected->sortorder, $record->sortorder); 451 $this->assertEquals($expected->idnumber, $record->idnumber); 452 $this->assertEquals($expected->id, $record->id); 453 $this->assertTrue($p->is_valid()); // Should always be valid after a save/update. 454 } 455 456 /** 457 * Test set_many prior to saving the persistent 458 */ 459 public function test_set_many_save(): void { 460 global $DB; 461 462 $persistent = (new core_testable_persistent(0, (object) [ 463 'idnumber' => 'test', 464 'sortorder' => 2 465 ])); 466 467 // Set multiple properties, and save. 468 $persistent->set_many([ 469 'idnumber' => 'test2', 470 'sortorder' => 1, 471 ])->save(); 472 473 // Confirm our persistent was saved. 474 $record = $DB->get_record(core_testable_persistent::TABLE, ['id' => $persistent->get('id')], '*', MUST_EXIST); 475 $this->assertEquals('test2', $record->idnumber); 476 $this->assertEquals(1, $record->sortorder); 477 } 478 479 /** 480 * Test set_many with empty array should not modify the persistent 481 */ 482 public function test_set_many_empty(): void { 483 global $DB; 484 485 $persistent = (new core_testable_persistent(0, (object) [ 486 'idnumber' => 'test', 487 'sortorder' => 2 488 ]))->create(); 489 490 // Set empty properties, and update. 491 $persistent->set_many([])->update(); 492 493 // Confirm our persistent was not updated. 494 $record = $DB->get_record(core_testable_persistent::TABLE, ['id' => $persistent->get('id')], '*', MUST_EXIST); 495 $this->assertEquals('test', $record->idnumber); 496 $this->assertEquals(2, $record->sortorder); 497 } 498 499 /** 500 * Test set with invalid property 501 */ 502 public function test_set_invalid_property(): void { 503 $persistent = (new core_testable_persistent(0, (object) [ 504 'idnumber' => 'test', 505 'sortorder' => 2 506 ])); 507 508 $this->expectException(coding_exception::class); 509 $this->expectExceptionMessage('Unexpected property \'invalid\' requested'); 510 $persistent->set('invalid', 'stuff'); 511 } 512 513 /** 514 * Test set_many with invalid property 515 */ 516 public function test_set_many_invalid_property(): void { 517 $persistent = (new core_testable_persistent(0, (object) [ 518 'idnumber' => 'test', 519 'sortorder' => 2 520 ])); 521 522 $this->expectException(coding_exception::class); 523 $this->expectExceptionMessage('Unexpected property \'invalid\' requested'); 524 $persistent->set_many(['invalid' => 'stuff']); 525 } 526 527 public function test_read() { 528 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 529 $p->create(); 530 unset($p->beforevalidate); 531 unset($p->beforecreate); 532 unset($p->aftercreate); 533 534 $p2 = new core_testable_persistent($p->get('id')); 535 $this->assertEquals($p, $p2); 536 537 $p3 = new core_testable_persistent(); 538 $p3->set('id', $p->get('id')); 539 $p3->read(); 540 $this->assertEquals($p, $p3); 541 } 542 543 public function test_delete() { 544 global $DB; 545 546 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 547 $p->create(); 548 $this->assertNotEquals(0, $p->get('id')); 549 $this->assertTrue($DB->record_exists_select(core_testable_persistent::TABLE, 'id = ?', array($p->get('id')))); 550 $this->assertFalse(isset($p->beforedelete)); 551 $this->assertFalse(isset($p->afterdelete)); 552 553 $p->delete(); 554 $this->assertFalse($DB->record_exists_select(core_testable_persistent::TABLE, 'id = ?', array($p->get('id')))); 555 $this->assertEquals(0, $p->get('id')); 556 $this->assertEquals(true, $p->beforedelete); 557 $this->assertEquals(true, $p->afterdelete); 558 } 559 560 public function test_has_property() { 561 $this->assertFalse(core_testable_persistent::has_property('unknown')); 562 $this->assertTrue(core_testable_persistent::has_property('idnumber')); 563 } 564 565 public function test_custom_setter_getter() { 566 global $DB; 567 568 $path = array(1, 2, 3); 569 $json = json_encode($path); 570 571 $p = new core_testable_persistent(0, (object) array('sortorder' => 0, 'idnumber' => 'abc')); 572 $p->set('path', $path); 573 $this->assertEquals($path, $p->get('path')); 574 $this->assertEquals($json, $p->to_record()->path); 575 576 $p->create(); 577 $record = $DB->get_record(core_testable_persistent::TABLE, array('id' => $p->get('id')), 'id, path', MUST_EXIST); 578 $this->assertEquals($json, $record->path); 579 } 580 581 /** 582 * Test get_record method for creating persistent instance 583 */ 584 public function test_get_record(): void { 585 $persistent = (new core_testable_persistent(0, (object) [ 586 'idnumber' => '123', 587 'sortorder' => 1, 588 ]))->create(); 589 590 $another = core_testable_persistent::get_record(['id' => $persistent->get('id')]); 591 592 // Assert we got back a persistent instance, and it matches original. 593 $this->assertInstanceOf(core_testable_persistent::class, $another); 594 $this->assertEquals($another->to_record(), $persistent->to_record()); 595 } 596 597 /** 598 * Test get_record method for creating persistent instance, ignoring a non-existing record 599 */ 600 public function test_get_record_ignore_missing(): void { 601 $persistent = core_testable_persistent::get_record(['id' => 42]); 602 $this->assertFalse($persistent); 603 } 604 605 /** 606 * Test get_record method for creating persistent instance, throws appropriate exception for non-existing record 607 */ 608 public function test_get_record_must_exist(): void { 609 $this->expectException(dml_missing_record_exception::class); 610 $this->expectExceptionMessage('Can\'t find data record in database table phpunit_persistent.'); 611 core_testable_persistent::get_record(['id' => 42], MUST_EXIST); 612 } 613 614 public function test_record_exists() { 615 global $DB; 616 $this->assertFalse($DB->record_exists(core_testable_persistent::TABLE, array('idnumber' => 'abc'))); 617 $p = new core_testable_persistent(0, (object) array('sortorder' => 123, 'idnumber' => 'abc')); 618 $p->create(); 619 $id = $p->get('id'); 620 $this->assertTrue(core_testable_persistent::record_exists($id)); 621 $this->assertTrue($DB->record_exists(core_testable_persistent::TABLE, array('idnumber' => 'abc'))); 622 $p->delete(); 623 $this->assertFalse(core_testable_persistent::record_exists($id)); 624 } 625 626 public function test_get_sql_fields() { 627 $expected = '' . 628 'c.id AS prefix_id, ' . 629 'c.shortname AS prefix_shortname, ' . 630 'c.idnumber AS prefix_idnumber, ' . 631 'c.description AS prefix_description, ' . 632 'c.descriptionformat AS prefix_descriptionformat, ' . 633 'c.parentid AS prefix_parentid, ' . 634 'c.path AS prefix_path, ' . 635 'c.sortorder AS prefix_sortorder, ' . 636 'c.scaleid AS prefix_scaleid, ' . 637 'c.timecreated AS prefix_timecreated, ' . 638 'c.timemodified AS prefix_timemodified, ' . 639 'c.usermodified AS prefix_usermodified'; 640 $this->assertEquals($expected, core_testable_persistent::get_sql_fields('c', 'prefix_')); 641 } 642 643 public function test_get_sql_fields_too_long() { 644 $this->expectException(coding_exception::class); 645 $this->expectExceptionMessageMatches('/The alias .+ exceeds 30 characters/'); 646 core_testable_persistent::get_sql_fields('c'); 647 } 648 649 public function test_get(): void { 650 $data = [ 651 'someint' => 123, 652 'intnull' => null, 653 'somefloat' => 33.44, 654 'sometext' => 'Hello', 655 'someraw' => '/dev/hello', 656 'booltrue' => true, 657 'boolfalse' => false, 658 ]; 659 $p = new core_testable_second_persistent(0, (object)$data); 660 $p->create(); 661 662 $this->assertSame($data['intnull'], $p->get('intnull')); 663 $this->assertSame($data['someint'], $p->get('someint')); 664 $this->assertIsFloat($p->get('somefloat')); // Avoid === comparisons on floats, verify type and value separated. 665 $this->assertEqualsWithDelta($data['somefloat'], $p->get('somefloat'), 0.00001); 666 $this->assertSame($data['sometext'], $p->get('sometext')); 667 $this->assertSame($data['someraw'], $p->get('someraw')); 668 $this->assertSame($data['booltrue'], $p->get('booltrue')); 669 $this->assertSame($data['boolfalse'], $p->get('boolfalse')); 670 671 // Ensure that types are correct after reloading data from database. 672 $p->read(); 673 674 $this->assertSame($data['someint'], $p->get('someint')); 675 $this->assertSame($data['intnull'], $p->get('intnull')); 676 $this->assertIsFloat($p->get('somefloat')); // Avoid === comparisons on floats, verify type and value separated. 677 $this->assertEqualsWithDelta($data['somefloat'], $p->get('somefloat'), 0.00001); 678 $this->assertSame($data['sometext'], $p->get('sometext')); 679 $this->assertSame($data['someraw'], $p->get('someraw')); 680 $this->assertSame($data['booltrue'], $p->get('booltrue')); 681 $this->assertSame($data['boolfalse'], $p->get('boolfalse')); 682 } 683 } 684 685 /** 686 * Example persistent class. 687 * 688 * @package core 689 * @copyright 2015 Frédéric Massart - FMCorz.net 690 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 691 */ 692 class core_testable_persistent extends persistent { 693 694 const TABLE = 'phpunit_persistent'; 695 696 protected static function define_properties() { 697 return array( 698 'shortname' => array( 699 'type' => PARAM_TEXT, 700 'default' => '' 701 ), 702 'idnumber' => array( 703 'type' => PARAM_TEXT, 704 ), 705 'description' => array( 706 'type' => PARAM_TEXT, 707 'default' => '' 708 ), 709 'descriptionformat' => array( 710 'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN), 711 'type' => PARAM_INT, 712 'default' => FORMAT_HTML 713 ), 714 'parentid' => array( 715 'type' => PARAM_INT, 716 'default' => 0 717 ), 718 'path' => array( 719 'type' => PARAM_RAW, 720 'default' => '' 721 ), 722 'sortorder' => array( 723 'type' => PARAM_INT, 724 'message' => new lang_string('invalidrequest', 'error') 725 ), 726 'scaleid' => array( 727 'type' => PARAM_INT, 728 'default' => null, 729 'null' => NULL_ALLOWED 730 ) 731 ); 732 } 733 734 protected function before_validate() { 735 $this->beforevalidate = true; 736 } 737 738 protected function before_create() { 739 $this->beforecreate = true; 740 } 741 742 protected function before_update() { 743 $this->beforeupdate = true; 744 } 745 746 protected function before_delete() { 747 $this->beforedelete = true; 748 } 749 750 protected function after_create() { 751 $this->aftercreate = true; 752 } 753 754 protected function after_update($result) { 755 $this->afterupdate = true; 756 } 757 758 protected function after_delete($result) { 759 $this->afterdelete = true; 760 } 761 762 protected function get_path() { 763 $value = $this->raw_get('path'); 764 if (!empty($value)) { 765 $value = json_decode($value); 766 } 767 return $value; 768 } 769 770 protected function set_path($value) { 771 if (!empty($value)) { 772 $value = json_encode($value); 773 } 774 $this->raw_set('path', $value); 775 } 776 777 protected function validate_sortorder($value) { 778 if ($value == 10) { 779 return new lang_string('invalidkey', 'error'); 780 } 781 return true; 782 } 783 784 } 785 786 /** 787 * Example persistent class to test types. 788 * 789 * @package core 790 * @copyright 2021 David Matamoros <davidmc@moodle.com> 791 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 792 */ 793 class core_testable_second_persistent extends persistent { 794 795 /** Table name for the persistent. */ 796 const TABLE = 'phpunit_second_persistent'; 797 798 /** 799 * Return the list of properties. 800 * 801 * @return array 802 */ 803 protected static function define_properties(): array { 804 return [ 805 'someint' => [ 806 'type' => PARAM_INT, 807 ], 808 'intnull' => [ 809 'type' => PARAM_INT, 810 'null' => NULL_ALLOWED, 811 'default' => null, 812 ], 813 'somefloat' => [ 814 'type' => PARAM_FLOAT, 815 ], 816 'sometext' => [ 817 'type' => PARAM_TEXT, 818 'default' => '' 819 ], 820 'someraw' => [ 821 'type' => PARAM_RAW, 822 'default' => '' 823 ], 824 'booltrue' => [ 825 'type' => PARAM_BOOL, 826 ], 827 'boolfalse' => [ 828 'type' => PARAM_BOOL, 829 ] 830 ]; 831 } 832 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body