Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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   * Unit tests for core_grades\component_gradeitems;
  19   *
  20   * @package   core_grades
  21   * @category  test
  22   * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU Public License
  24   */
  25  
  26  declare(strict_types = 1);
  27  
  28  namespace tests\core_grades {
  29  
  30      use advanced_testcase;
  31      use core_grades\component_gradeitems;
  32      use coding_exception;
  33  
  34      /**
  35       * Unit tests for core_grades\component_gradeitems;
  36       *
  37       * @package   core_grades
  38       * @category  test
  39       * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
  40       * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41       */
  42      class component_gradeitems_test extends advanced_testcase {
  43  
  44          /**
  45           * Ensure that a component which does not implement the mapping class excepts.
  46           */
  47          public function test_get_itemname_mapping_for_component_does_not_exist(): void {
  48              $mappings = component_gradeitems::get_itemname_mapping_for_component('invalid_component');
  49              $this->assertIsArray($mappings);
  50              $this->assertCount(1, $mappings);
  51              $this->assertArrayHasKey(0, $mappings);
  52          }
  53  
  54          /**
  55           * Ensure that a component which does not implement the mapping class correctly excepts.
  56           */
  57          public function test_get_itemname_mapping_for_valid_component_invalid_mapping(): void {
  58              $this->expectException(coding_exception::class);
  59              component_gradeitems::get_itemname_mapping_for_component('tests\core_grades\component_gradeitems\invalid');
  60          }
  61  
  62          /**
  63           * Ensure that a component which implements the mapping class correctly eets the correct set of mappings.
  64           */
  65          public function test_get_itemname_mapping_for_valid_component_valid_mapping(): void {
  66              $mapping = component_gradeitems::get_itemname_mapping_for_component('tests\core_grades\component_gradeitems\valid');
  67              $this->assertIsArray($mapping);
  68              $this->assertEquals([
  69                  0 => 'rating',
  70                  1 => 'someother',
  71              ], $mapping);
  72          }
  73  
  74          /**
  75           * Data provider for is_valid_itemname tests.
  76           *
  77           * @return array
  78           */
  79          public function is_valid_itemname_provider(): array {
  80              return [
  81                  'valid' => [
  82                      'someother',
  83                      true,
  84                  ],
  85                  'validnotadvanced' => [
  86                      'rating',
  87                      true,
  88                  ],
  89                  'invalid' => [
  90                      'doesnotexist',
  91                      false,
  92                  ],
  93              ];
  94          }
  95  
  96          /**
  97           * Ensure that a component implementing advanced grading returns the correct areas.
  98           *
  99           * @dataProvider is_valid_itemname_provider
 100           * @param string $itemname
 101           * @param bool $isadvanced
 102           */
 103          public function test_is_valid_itemname(string $itemname, bool $isadvanced): void {
 104              $this->assertEquals(
 105                  $isadvanced,
 106                  component_gradeitems::is_valid_itemname('tests\core_grades\component_gradeitems\valid_and_advanced', $itemname)
 107              );
 108          }
 109  
 110  
 111          /**
 112           * Ensure that a component which does not implement the advancedgrading interface returns this.
 113           */
 114          public function test_defines_advancedgrading_itemnames_for_component_does_not_exist(): void {
 115              $this->assertFalse(component_gradeitems::defines_advancedgrading_itemnames_for_component('invalid_component'));
 116          }
 117  
 118          /**
 119           * Ensure that a component which does not implement the advancedgrading interface returns this.
 120           */
 121          public function test_defines_advancedgrading_itemnames_for_component_no_interfaces(): void {
 122              $this->assertFalse(component_gradeitems::defines_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\invalid'));
 123          }
 124  
 125          /**
 126           * Ensure that a component which implements the item mapping but not implement the advancedgrading interface returns this.
 127           */
 128          public function test_defines_advancedgrading_itemnames_for_component_grading_no_interface(): void {
 129              $this->assertFalse(component_gradeitems::defines_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\valid'));
 130          }
 131  
 132          /**
 133           * Ensure that a component which implements the item mapping but not implement the advancedgrading interface returns this.
 134           */
 135          public function test_defines_advancedgrading_itemnames_for_component_grading_has_interface(): void {
 136              $this->assertTrue(component_gradeitems::defines_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\valid_and_advanced'));
 137          }
 138  
 139          /**
 140           * Ensure that a component which does not implement the advancedgrading interface returns this.
 141           */
 142          public function test_get_advancedgrading_itemnames_for_component_does_not_exist(): void {
 143              $this->expectException(coding_exception::class);
 144              component_gradeitems::get_advancedgrading_itemnames_for_component('invalid_component');
 145          }
 146  
 147          /**
 148           * Ensure that a component which does not implement the advancedgrading interface returns this.
 149           */
 150          public function test_get_advancedgrading_itemnames_for_component_no_interfaces(): void {
 151              $this->expectException(coding_exception::class);
 152              component_gradeitems::get_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\invalid');
 153          }
 154  
 155          /**
 156           * Ensure that a component which implements the item mapping but not implement the advancedgrading interface returns this.
 157           */
 158          public function test_get_advancedgrading_itemnames_for_component_grading_no_interface(): void {
 159              $this->expectException(coding_exception::class);
 160              component_gradeitems::get_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\valid');
 161          }
 162  
 163          /**
 164           * Ensure that a component implementing advanced grading returns the correct areas.
 165           */
 166          public function test_get_advancedgrading_itemnames_for_component(): void {
 167              $areas = component_gradeitems::get_advancedgrading_itemnames_for_component('tests\core_grades\component_gradeitems\valid_and_advanced');
 168              $this->assertEquals(['someother'], $areas);
 169          }
 170  
 171          /**
 172           * Data provider for is_advancedgrading_itemname tests.
 173           *
 174           * @return array
 175           */
 176          public function is_advancedgrading_itemname_provider(): array {
 177              return [
 178                  'valid' => [
 179                      'someother',
 180                      true,
 181                  ],
 182                  'validnotadvanced' => [
 183                      'rating',
 184                      false,
 185                  ],
 186                  'invalid' => [
 187                      'doesnotexist',
 188                      false,
 189                  ],
 190              ];
 191          }
 192  
 193          /**
 194           * Ensure that a component implementing advanced grading returns the correct areas.
 195           *
 196           * @dataProvider is_advancedgrading_itemname_provider
 197           * @param string $itemname
 198           * @param bool $isadvanced
 199           */
 200          public function test_is_advancedgrading_itemname(string $itemname, bool $isadvanced): void {
 201              $this->assertEquals(
 202                  $isadvanced,
 203                  component_gradeitems::is_advancedgrading_itemname('tests\core_grades\component_gradeitems\valid_and_advanced', $itemname)
 204              );
 205          }
 206  
 207          /**
 208           * Data provider for get_field_name_for_itemnumber.
 209           *
 210           * @return array
 211           */
 212          public function get_field_name_for_itemnumber_provider(): array {
 213              return [
 214                  'Valid itemnumber 0 case 1' => [
 215                      0,
 216                      'gradecat',
 217                      'gradecat',
 218                  ],
 219                  'Valid itemnumber 0 case 2' => [
 220                      0,
 221                      'melon',
 222                      'melon',
 223                  ],
 224                  'Valid itemnumber 1 case 1' => [
 225                      1,
 226                      'gradecat',
 227                      'gradecat_someother',
 228                  ],
 229                  'Valid itemnumber 1 case 2' => [
 230                      1,
 231                      'melon',
 232                      'melon_someother',
 233                  ],
 234              ];
 235          }
 236  
 237          /**
 238           * Ensure that valid field names are correctly mapped for a valid component.
 239           *
 240           * @dataProvider get_field_name_for_itemnumber_provider
 241           * @param int $itemnumber The item itemnumber to test
 242           * @param string $fieldname The field name being translated
 243           * @param string $expected The expected value
 244           */
 245          public function test_get_field_name_for_itemnumber(int $itemnumber, string $fieldname, string $expected): void {
 246              $component = 'tests\core_grades\component_gradeitems\valid';
 247              $this->assertEquals($expected, component_gradeitems::get_field_name_for_itemnumber($component, $itemnumber, $fieldname));
 248          }
 249  
 250          /**
 251           * Ensure that an invalid itemnumber does not provide any field name.
 252           */
 253          public function test_get_field_name_for_itemnumber_invalid_itemnumber(): void {
 254              $component = 'tests\core_grades\component_gradeitems\valid';
 255  
 256              $this->expectException(coding_exception::class);
 257              component_gradeitems::get_field_name_for_itemnumber($component, 100, 'gradecat');
 258          }
 259  
 260          /**
 261           * Ensure that a component which does not define a mapping can still get a mapping for itemnumber 0.
 262           */
 263          public function test_get_field_name_for_itemnumber_component_not_defining_mapping_itemnumber_zero(): void {
 264              $component = 'tests\core_grades\othervalid';
 265  
 266              $this->assertEquals('gradecat', component_gradeitems::get_field_name_for_itemnumber($component, 0, 'gradecat'));
 267          }
 268  
 269          /**
 270           * Ensure that a component which does not define a mapping cannot get a mapping for itemnumber 1+.
 271           */
 272          public function test_get_field_name_for_itemnumber_component_not_defining_mapping_itemnumber_nonzero(): void {
 273              $component = 'tests\core_grades\othervalid';
 274  
 275              $this->expectException(coding_exception::class);
 276              component_gradeitems::get_field_name_for_itemnumber($component, 100, 'gradecat');
 277          }
 278  
 279          /**
 280           * Ensure that a component which incorrectly defines a mapping cannot get a mapping for itemnumber 1+.
 281           */
 282          public function test_get_field_name_for_itemnumber_component_invalid_mapping_itemnumber_nonzero(): void {
 283              $component = 'tests\core_grades\component_gradeitems\invalid';
 284  
 285              $this->expectException(coding_exception::class);
 286              component_gradeitems::get_field_name_for_itemnumber($component, 100, 'gradecat');
 287          }
 288  
 289          /**
 290           * Data provider for get_field_name_for_itemname.
 291           *
 292           * @return array
 293           */
 294          public function get_field_name_for_itemname_provider(): array {
 295              return [
 296                  'Empty itemname empty case 1' => [
 297                      '',
 298                      'gradecat',
 299                      'gradecat',
 300                  ],
 301                  'Empty itemname empty case 2' => [
 302                      '',
 303                      'melon',
 304                      'melon',
 305                  ],
 306                  'First itemname empty case 1' => [
 307                      'rating',
 308                      'gradecat',
 309                      'gradecat',
 310                  ],
 311                  'First itemname empty case 2' => [
 312                      'rating',
 313                      'melon',
 314                      'melon',
 315                  ],
 316                  'Other itemname empty case 1' => [
 317                      'someother',
 318                      'gradecat',
 319                      'gradecat_someother',
 320                  ],
 321                  'Other itemname empty case 2' => [
 322                      'someother',
 323                      'melon',
 324                      'melon_someother',
 325                  ],
 326              ];
 327          }
 328  
 329          /**
 330           * Ensure that valid field names are correctly mapped for a valid component.
 331           *
 332           * @dataProvider get_field_name_for_itemname_provider
 333           * @param string $itemname The item itemname to test
 334           * @param string $fieldname The field name being translated
 335           * @param string $expected The expected value
 336           */
 337          public function test_get_field_name_for_itemname(string $itemname, string $fieldname, string $expected): void {
 338              $component = 'tests\core_grades\component_gradeitems\valid';
 339              $this->assertEquals($expected, component_gradeitems::get_field_name_for_itemname($component, $itemname, $fieldname));
 340          }
 341  
 342          /**
 343           * Ensure that an invalid itemname does not provide any field name.
 344           */
 345          public function test_get_field_name_for_itemname_invalid_itemname(): void {
 346              $component = 'tests\core_grades\component_gradeitems\valid';
 347  
 348              $this->expectException(coding_exception::class);
 349              component_gradeitems::get_field_name_for_itemname($component, 'typo', 'gradecat');
 350          }
 351  
 352          /**
 353           * Ensure that an empty itemname provides a matching fieldname regardless of whether the component exists or
 354           * not.
 355           */
 356          public function test_get_field_name_for_itemname_not_defining_mapping_empty_name(): void {
 357              $component = 'tests\core_grades\othervalid';
 358  
 359              $this->assertEquals('gradecat', component_gradeitems::get_field_name_for_itemname($component, '', 'gradecat'));
 360          }
 361  
 362          /**
 363           * Ensure that an valid component with some itemname excepts.
 364           */
 365          public function test_get_field_name_for_itemname_not_defining_mapping_with_name(): void {
 366              $component = 'tests\core_grades\othervalid';
 367  
 368              $this->expectException(coding_exception::class);
 369              component_gradeitems::get_field_name_for_itemname($component, 'example', 'gradecat');
 370          }
 371  
 372          /**
 373           * Ensure that an empty itemname provides a matching fieldname even if the mapping is invalid.
 374           */
 375          public function test_get_field_name_for_itemname_invalid_mapping_empty_name(): void {
 376              $component = 'tests\core_grades\component_gradeitems\invalid';
 377  
 378              $this->assertEquals('gradecat', component_gradeitems::get_field_name_for_itemname($component, '', 'gradecat'));
 379          }
 380  
 381          /**
 382           * Ensure that an invalid mapping with some itemname excepts.
 383           */
 384          public function test_get_field_name_for_itemname_invalid_mapping_with_name(): void {
 385              $component = 'tests\core_grades\component_gradeitems\invalid';
 386  
 387              $this->expectException(coding_exception::class);
 388              component_gradeitems::get_field_name_for_itemname($component, 'example', 'gradecat');
 389          }
 390  
 391          /**
 392           * Data provider for get_itemname_from_itemnumber.
 393           *
 394           * @return array
 395           */
 396          public function get_itemname_from_itemnumber_provider(): array {
 397              return [
 398                  'Valid itemnumber 0' => [
 399                      0,
 400                      '',
 401                  ],
 402                  'Valid itemnumber 1' => [
 403                      1,
 404                      'someother',
 405                  ],
 406              ];
 407          }
 408  
 409          /**
 410           * Ensure that item names are correctly mapped for a valid component.
 411           *
 412           * @dataProvider get_itemname_from_itemnumber_provider
 413           * @param int $itemnumber The item itemnumber to test
 414           * @param string $expected The expected value
 415           */
 416          public function test_get_itemname_from_itemnumber(int $itemnumber, string $expected): void {
 417              $component = 'tests\core_grades\component_gradeitems\valid';
 418              $this->assertEquals($expected, component_gradeitems::get_itemname_from_itemnumber($component, $itemnumber));
 419          }
 420  
 421          /**
 422           * Ensure that an itemnumber over 1000 is treated as itemnumber 0 for the purpose of outcomes.
 423           */
 424          public function test_get_itemname_from_itemnumber_outcome_itemnumber(): void {
 425              $component = 'tests\core_grades\component_gradeitems\valid';
 426  
 427              $this->assertEquals('', component_gradeitems::get_itemname_from_itemnumber($component, 1000));
 428          }
 429  
 430          /**
 431           * Ensure that an invalid itemnumber does not provide any field name.
 432           */
 433          public function test_get_itemname_from_itemnumber_invalid_itemnumber(): void {
 434              $component = 'tests\core_grades\component_gradeitems\valid';
 435  
 436              $this->expectException(coding_exception::class);
 437              component_gradeitems::get_itemname_from_itemnumber($component, 100);
 438          }
 439  
 440          /**
 441           * Ensure that a component which does not define a mapping can still get a mapping for itemnumber 0.
 442           */
 443          public function test_get_itemname_from_itemnumber_component_not_defining_mapping_itemnumber_zero(): void {
 444              $component = 'tests\core_grades\othervalid';
 445  
 446              $this->assertEquals('', component_gradeitems::get_itemname_from_itemnumber($component, 0));
 447          }
 448  
 449          /**
 450           * Ensure that a component which does not define a mapping cannot get a mapping for itemnumber 1+.
 451           */
 452          public function test_get_itemname_from_itemnumber_component_not_defining_mapping_itemnumber_nonzero(): void {
 453              $component = 'tests\core_grades\othervalid';
 454  
 455              $this->expectException(coding_exception::class);
 456              component_gradeitems::get_itemname_from_itemnumber($component, 100);
 457          }
 458  
 459          /**
 460           * Ensure that a component which incorrectly defines a mapping cannot get a mapping for itemnumber 1+.
 461           */
 462          public function test_get_itemname_from_itemnumber_component_invalid_mapping_itemnumber_nonzero(): void {
 463              $component = 'tests\core_grades\component_gradeitems\invalid';
 464  
 465              $this->expectException(coding_exception::class);
 466              component_gradeitems::get_itemname_from_itemnumber($component, 100);
 467          }
 468  
 469          /**
 470           * Data provider for get_itemname_from_itemnumber.
 471           *
 472           * @return array
 473           */
 474          public function get_itemnumber_from_itemname_provider(): array {
 475              return [
 476                  'Empty itemname empty' => [
 477                      '',
 478                      0,
 479                  ],
 480                  'First itemname empty' => [
 481                      'rating',
 482                      0,
 483                  ],
 484                  'Other itemname empty' => [
 485                      'someother',
 486                      1,
 487                  ],
 488              ];
 489          }
 490  
 491          /**
 492           * Ensure that valid item names are correctly mapped for a valid component.
 493           *
 494           * @dataProvider get_itemnumber_from_itemname_provider
 495           * @param string $itemname The item itemname to test
 496           * @param int $expected The expected value
 497           */
 498          public function test_get_itemnumber_from_itemname(string $itemname, int $expected): void {
 499              $component = 'tests\core_grades\component_gradeitems\valid';
 500              $this->assertEquals($expected, component_gradeitems::get_itemnumber_from_itemname($component, $itemname));
 501          }
 502  
 503          /**
 504           * Ensure that an invalid itemname excepts.
 505           */
 506          public function test_get_itemnumber_from_itemname_invalid_itemname(): void {
 507              $component = 'tests\core_grades\component_gradeitems\valid';
 508  
 509              $this->expectException(coding_exception::class);
 510              component_gradeitems::get_itemnumber_from_itemname($component, 'typo');
 511          }
 512  
 513          /**
 514           * Ensure that an empty itemname provides a correct itemnumber regardless of whether the component exists or
 515           * not.
 516           */
 517          public function test_get_itemnumber_from_itemname_not_defining_mapping_empty_name(): void {
 518              $component = 'tests\core_grades\component_gradeitems\othervalid';
 519  
 520              $this->assertEquals(0, component_gradeitems::get_itemnumber_from_itemname($component, ''));
 521          }
 522  
 523          /**
 524           * Ensure that an valid component with some itemname excepts.
 525           */
 526          public function test_get_itemnumber_from_itemname_not_defining_mapping_with_name(): void {
 527              $component = 'tests\core_grades\component_gradeitems\othervalid';
 528  
 529              $this->expectException(coding_exception::class);
 530              component_gradeitems::get_itemnumber_from_itemname($component, 'example');
 531          }
 532  
 533          /**
 534           * Ensure that an empty itemname provides a matching fieldname even if the mapping is invalid.
 535           */
 536          public function test_get_itemnumber_from_itemname_invalid_mapping_empty_name(): void {
 537              $component = 'tests\core_grades\component_gradeitems\invalid';
 538  
 539              $this->assertEquals(0, component_gradeitems::get_itemnumber_from_itemname($component, ''));
 540          }
 541  
 542          /**
 543           * Ensure that an invalid mapping with some itemname excepts.
 544           */
 545          public function test_get_itemnumber_from_itemname_invalid_mapping_with_name(): void {
 546              $component = 'tests\core_grades\component_gradeitems\invalid';
 547  
 548              $this->expectException(coding_exception::class);
 549              component_gradeitems::get_itemnumber_from_itemname($component, 'example');
 550          }
 551      }
 552  }
 553  
 554  namespace tests\core_grades\component_gradeitems\valid\grades {
 555      use core_grades\local\gradeitem\itemnumber_mapping;
 556  
 557      /**
 558       * Valid class for testing mappings.
 559       *
 560       * @package   core_grades
 561       * @category  test
 562       * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
 563       * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 564       */
 565      class gradeitems implements itemnumber_mapping {
 566          /**
 567           * Get the grade item mapping of item number to item name.
 568           *
 569           * @return array
 570           */
 571          public static function get_itemname_mapping_for_component(): array {
 572              return [
 573                  0 => 'rating',
 574                  1 => 'someother',
 575              ];
 576          }
 577      }
 578  }
 579  
 580  namespace tests\core_grades\component_gradeitems\valid_and_advanced\grades {
 581      use core_grades\local\gradeitem\itemnumber_mapping;
 582      use core_grades\local\gradeitem\advancedgrading_mapping;
 583  
 584      /**
 585       * Valid class for testing mappings.
 586       *
 587       * @package   core_grades
 588       * @category  test
 589       * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
 590       * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 591       */
 592      class gradeitems implements itemnumber_mapping, advancedgrading_mapping {
 593          /**
 594           * Get the grade item mapping of item number to item name.
 595           *
 596           * @return array
 597           */
 598          public static function get_itemname_mapping_for_component(): array {
 599              return [
 600                  0 => 'rating',
 601                  1 => 'someother',
 602              ];
 603          }
 604  
 605          /**
 606           * Get the list of items which define advanced grading.
 607           *
 608           * @return array
 609           */
 610          public static function get_advancedgrading_itemnames(): array {
 611              return [
 612                  'someother',
 613              ];
 614          }
 615      }
 616  }
 617  
 618  namespace tests\core_grades\component_gradeitems\invalid\grades {
 619      use core_grades\local\gradeitem\itemnumber_mapping;
 620  
 621      /**
 622       * Invalid class for testing mappings.
 623       *
 624       * @package   core_grades
 625       * @category  test
 626       * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
 627       * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 628       */
 629      class gradeitems {
 630          /**
 631           * Get the grade item mapping of item number to item name.
 632           *
 633           * @return array
 634           */
 635          public static function get_itemname_mapping_for_component(): array {
 636              return [
 637                  0 => 'rating',
 638                  1 => 'someother',
 639              ];
 640          }
 641  
 642          /**
 643           * Get the list of items which define advanced grading.
 644           *
 645           * @return array
 646           */
 647          public static function get_advancedgrading_itemnames(): array {
 648              return [
 649                  1 => 'someother',
 650              ];
 651          }
 652      }
 653  }