Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [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  namespace mod_data;
  18  
  19  use context_module;
  20  use rating_manager;
  21  use stdClass;
  22  
  23  /**
  24   * Template tests class for mod_data.
  25   *
  26   * @package    mod_data
  27   * @category   test
  28   * @copyright  2022 Ferran Recio <ferran@moodle.com>
  29   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   * @coversDefaultClass \mod_data\template
  31   */
  32  class template_test extends \advanced_testcase {
  33      /**
  34       * Setup to ensure that fixtures are loaded.
  35       */
  36      public static function setupBeforeClass(): void {
  37          global $CFG;
  38          require_once($CFG->dirroot . '/rating/lib.php');
  39      }
  40  
  41      /**
  42       * Test for static create methods.
  43       *
  44       * @covers ::parse_entries
  45       * @dataProvider parse_entries_provider
  46       * @param string $templatecontent the template string
  47       * @param string $expected expected output
  48       * @param string $rolename the user rolename
  49       * @param bool $enableexport is portfolio export is enabled
  50       * @param bool $approved if the entry is approved
  51       * @param bool $enablecomments is comments are enabled
  52       * @param bool $enableratings if ratings are enabled
  53       * @param array $options extra parser options
  54       * @param bool $otherauthor if the entry is from another user
  55       */
  56      public function test_parse_entries(
  57          string $templatecontent,
  58          string $expected,
  59          string $rolename = 'editingteacher',
  60          bool $enableexport = false,
  61          bool $approved = true,
  62          bool $enablecomments = false,
  63          bool $enableratings = false,
  64          array $options = [],
  65          bool $otherauthor = false
  66      ) {
  67          global $DB, $PAGE;
  68          // Comments, tags, approval, user role.
  69          $this->resetAfterTest();
  70  
  71          $params = ['approval' => true];
  72  
  73          // Enable comments.
  74          if ($enablecomments) {
  75              set_config('usecomments', 1);
  76              $params['comments'] = true;
  77              $PAGE->reset_theme_and_output();
  78              $PAGE->set_url('/mod/data/view.php');
  79          }
  80  
  81          $course = $this->getDataGenerator()->create_course();
  82          $params['course'] = $course;
  83          $activity = $this->getDataGenerator()->create_module('data', $params);
  84          $cm = get_coursemodule_from_id('data', $activity->cmid, 0, false, MUST_EXIST);
  85          $context = context_module::instance($cm->id);
  86  
  87          $user = $this->getDataGenerator()->create_user();
  88          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
  89          $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids[$rolename]);
  90          $author = $user;
  91  
  92          if ($otherauthor) {
  93              $user2 = $this->getDataGenerator()->create_user();
  94              $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleids[$rolename]);
  95              $author = $user2;
  96          }
  97  
  98          // Generate an entry.
  99          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 100          $fieldrecord = (object)[
 101              'name' => 'myfield',
 102              'type' => 'text',
 103          ];
 104          $field = $generator->create_field($fieldrecord, $activity);
 105  
 106          $this->setUser($user);
 107  
 108          $entryid = $generator->create_entry(
 109              $activity,
 110              [$field->field->id => 'Example entry'],
 111              0,
 112              ['Cats', 'Dogs'],
 113              ['approved' => $approved]
 114          );
 115  
 116          if ($enableexport) {
 117              $this->enable_portfolio($user);
 118          }
 119  
 120          $manager = manager::create_from_instance($activity);
 121  
 122          $entry = (object)[
 123              'id' => $entryid,
 124              'approved' => $approved,
 125              'timecreated' => 1657618639,
 126              'timemodified' => 1657618650,
 127              'userid' => $author->id,
 128              'groupid' => 0,
 129              'dataid' => $activity->id,
 130              'picture' => 0,
 131              'firstname' => $author->firstname,
 132              'lastname' => $author->lastname,
 133              'firstnamephonetic' => $author->firstnamephonetic,
 134              'lastnamephonetic' => $author->lastnamephonetic,
 135              'middlename' => $author->middlename,
 136              'alternatename' => $author->alternatename,
 137              'imagealt' => 'PIXEXAMPLE',
 138              'email' => $author->email,
 139          ];
 140          $entries = [$entry];
 141  
 142          if ($enableratings) {
 143              $entries = $this->enable_ratings($context, $activity, $entries, $user);
 144          }
 145  
 146          // Some cooked variables for the regular expression.
 147          $replace = [
 148              '{authorfullname}' => fullname($author),
 149              '{timeadded}' => userdate($entry->timecreated, get_string('strftimedatemonthabbr', 'langconfig')),
 150              '{timemodified}' => userdate($entry->timemodified, get_string('strftimedatemonthabbr', 'langconfig')),
 151              '{fieldid}' => $field->field->id,
 152              '{entryid}' => $entry->id,
 153              '{cmid}' => $cm->id,
 154              '{courseid}' => $course->id,
 155              '{authorid}' => $author->id
 156          ];
 157  
 158          $parser = new template($manager, $templatecontent, $options);
 159          $result = $parser->parse_entries($entries);
 160  
 161          // We don't want line breaks for the validations.
 162          $result = str_replace("\n", '', $result);
 163          $regexp = str_replace(array_keys($replace), array_values($replace), $expected);
 164          $this->assertMatchesRegularExpression($regexp, $result);
 165      }
 166  
 167      /**
 168       * Data provider for test_parse_entries().
 169       *
 170       * @return array of scenarios
 171       */
 172      public function parse_entries_provider(): array {
 173          return [
 174              // Teacher scenarios.
 175              'Teacher id tag' => [
 176                  'templatecontent' => 'Some ##id## tag',
 177                  'expected' => '|Some {entryid} tag|',
 178                  'rolename' => 'editingteacher',
 179              ],
 180              'Teacher delete tag' => [
 181                  'templatecontent' => 'Some ##delete## tag',
 182                  'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 183                  'rolename' => 'editingteacher',
 184              ],
 185              'Teacher edit tag' => [
 186                  'templatecontent' => 'Some ##edit## tag',
 187                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
 188                  'rolename' => 'editingteacher',
 189              ],
 190              'Teacher more tag' => [
 191                  'templatecontent' => 'Some ##more## tag',
 192                  'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
 193                  'rolename' => 'editingteacher',
 194                  'enableexport' => false,
 195                  'approved' => true,
 196                  'enablecomments' => false,
 197                  'enableratings' => false,
 198                  'options' => ['showmore' => true],
 199              ],
 200              'Teacher more tag with showmore set to false' => [
 201                  'templatecontent' => 'Some ##more## tag',
 202                  'expected' => '|Some  tag|',
 203                  'rolename' => 'editingteacher',
 204                  'enableexport' => false,
 205                  'approved' => true,
 206                  'enablecomments' => false,
 207                  'enableratings' => false,
 208                  'options' => ['showmore' => false],
 209              ],
 210              'Teacher moreurl tag' => [
 211                  'templatecontent' => 'Some ##moreurl## tag',
 212                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 213                  'rolename' => 'editingteacher',
 214                  'enableexport' => false,
 215                  'approved' => true,
 216                  'enablecomments' => false,
 217                  'enableratings' => false,
 218                  'options' => ['showmore' => true],
 219              ],
 220              'Teacher moreurl tag with showmore set to false' => [
 221                  'templatecontent' => 'Some ##moreurl## tag',
 222                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 223                  'rolename' => 'editingteacher',
 224                  'enableexport' => false,
 225                  'approved' => true,
 226                  'enablecomments' => false,
 227                  'enableratings' => false,
 228                  'options' => ['showmore' => false],
 229              ],
 230              'Teacher delcheck tag' => [
 231                  'templatecontent' => 'Some ##delcheck## tag',
 232                  'expected' => '|Some .*input.*checkbox.*value.*{entryid}.* tag|',
 233                  'rolename' => 'editingteacher',
 234              ],
 235              'Teacher user tag' => [
 236                  'templatecontent' => 'Some ##user## tag',
 237                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
 238                  'rolename' => 'editingteacher',
 239              ],
 240              'Teacher userpicture tag' => [
 241                  'templatecontent' => 'Some ##userpicture## tag',
 242                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
 243                  'rolename' => 'editingteacher',
 244              ],
 245              'Teacher export tag' => [
 246                  'templatecontent' => 'Some ##export## tag',
 247                  'expected' => '|Some .*portfolio/add.* tag|',
 248                  'rolename' => 'editingteacher',
 249                  'enableexport' => true,
 250              ],
 251              'Teacher export tag not configured' => [
 252                  'templatecontent' => 'Some ##export## tag',
 253                  'expected' => '|Some  tag|',
 254                  'rolename' => 'editingteacher',
 255                  'enableexport' => false,
 256              ],
 257              'Teacher timeadded tag' => [
 258                  'templatecontent' => 'Some ##timeadded## tag',
 259                  'expected' => '|Some <span.*>{timeadded}</span> tag|',
 260                  'rolename' => 'editingteacher',
 261              ],
 262              'Teacher timemodified tag' => [
 263                  'templatecontent' => 'Some ##timemodified## tag',
 264                  'expected' => '|Some <span.*>{timemodified}</span> tag|',
 265                  'rolename' => 'editingteacher',
 266              ],
 267              'Teacher approve tag approved entry' => [
 268                  'templatecontent' => 'Some ##approve## tag',
 269                  'expected' => '|Some  tag|',
 270                  'rolename' => 'editingteacher',
 271                  'enableexport' => false,
 272                  'approved' => true,
 273              ],
 274              'Teacher approve tag disapproved entry' => [
 275                  'templatecontent' => 'Some ##approve## tag',
 276                  'expected' => '|Some .*approve.*{entryid}.*sesskey.*Approve.* tag|',
 277                  'rolename' => 'editingteacher',
 278                  'enableexport' => false,
 279                  'approved' => false,
 280              ],
 281              'Teacher disapprove tag approved entry' => [
 282                  'templatecontent' => 'Some ##disapprove## tag',
 283                  'expected' => '|Some .*disapprove.*{entryid}.*sesskey.*Undo approval.* tag|',
 284                  'rolename' => 'editingteacher',
 285                  'enableexport' => false,
 286                  'approved' => true,
 287              ],
 288              'Teacher disapprove tag disapproved entry' => [
 289                  'templatecontent' => 'Some ##disapprove## tag',
 290                  'expected' => '|Some  tag|',
 291                  'rolename' => 'editingteacher',
 292                  'enableexport' => false,
 293                  'approved' => false,
 294              ],
 295              'Teacher approvalstatus tag approved entry' => [
 296                  'templatecontent' => 'Some ##approvalstatus## tag',
 297                  'expected' => '|Some  tag|', // We do not display the approval status anymore.
 298                  'rolename' => 'editingteacher',
 299                  'enableexport' => false,
 300                  'approved' => true,
 301              ],
 302              'Teacher approvalstatus tag disapproved entry' => [
 303                  'templatecontent' => 'Some ##approvalstatus## tag',
 304                  'expected' => '|Some .*Pending approval.* tag|',
 305                  'rolename' => 'editingteacher',
 306                  'enableexport' => false,
 307                  'approved' => false,
 308              ],
 309              'Teacher approvalstatusclass tag approved entry' => [
 310                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 311                  'expected' => '|Some approved tag|',
 312                  'rolename' => 'editingteacher',
 313                  'enableexport' => false,
 314                  'approved' => true,
 315              ],
 316              'Teacher approvalstatusclass tag disapproved entry' => [
 317                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 318                  'expected' => '|Some notapproved tag|',
 319                  'rolename' => 'editingteacher',
 320                  'enableexport' => false,
 321                  'approved' => false,
 322              ],
 323              'Teacher tags tag' => [
 324                  'templatecontent' => 'Some ##tags## tag',
 325                  'expected' => '|Some .*Cats.* tag|',
 326                  'rolename' => 'editingteacher',
 327              ],
 328              'Teacher field name tag' => [
 329                  'templatecontent' => 'Some [[myfield]] tag',
 330                  'expected' => '|Some .*Example entry.* tag|',
 331                  'rolename' => 'editingteacher',
 332              ],
 333              'Teacher field#id name tag' => [
 334                  'templatecontent' => 'Some [[myfield#id]] tag',
 335                  'expected' => '|Some {fieldid} tag|',
 336                  'rolename' => 'editingteacher',
 337              ],
 338              'Teacher comments name tag with comments enabled' => [
 339                  'templatecontent' => 'Some ##comments## tag',
 340                  'expected' => '|Some .*Comments.* tag|',
 341                  'rolename' => 'editingteacher',
 342                  'enableexport' => false,
 343                  'approved' => true,
 344                  'enablecomments' => true,
 345              ],
 346              'Teacher comments name tag with comments disabled' => [
 347                  'templatecontent' => 'Some ##comments## tag',
 348                  'expected' => '|Some  tag|',
 349                  'rolename' => 'editingteacher',
 350                  'enableexport' => false,
 351                  'approved' => true,
 352                  'enablecomments' => false,
 353              ],
 354              'Teacher comment forced with comments enables' => [
 355                  'templatecontent' => 'No tags',
 356                  'expected' => '|No tags.*Comments.*|',
 357                  'rolename' => 'editingteacher',
 358                  'enableexport' => false,
 359                  'approved' => true,
 360                  'enablecomments' => true,
 361                  'enableratings' => false,
 362                  'options' => ['comments' => true],
 363              ],
 364              'Teacher comment forced without comments enables' => [
 365                  'templatecontent' => 'No tags',
 366                  'expected' => '|^No tags$|',
 367                  'rolename' => 'editingteacher',
 368                  'enableexport' => false,
 369                  'approved' => true,
 370                  'enablecomments' => false,
 371                  'enableratings' => false,
 372                  'options' => ['comments' => true],
 373              ],
 374              'Teacher adding ratings without ratings configured' => [
 375                  'templatecontent' => 'No tags',
 376                  'expected' => '|^No tags$|',
 377                  'rolename' => 'editingteacher',
 378                  'enableexport' => false,
 379                  'approved' => true,
 380                  'enablecomments' => false,
 381                  'enableratings' => false,
 382                  'options' => ['ratings' => true],
 383              ],
 384              'Teacher adding ratings with ratings configured' => [
 385                  'templatecontent' => 'No tags',
 386                  'expected' => '|^No tags.*Average of ratings|',
 387                  'rolename' => 'editingteacher',
 388                  'enableexport' => false,
 389                  'approved' => true,
 390                  'enablecomments' => false,
 391                  'enableratings' => true,
 392                  'options' => ['ratings' => true],
 393              ],
 394              'Teacher actionsmenu tag with default options' => [
 395                  'templatecontent' => 'Some ##actionsmenu## tag',
 396                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 397                  'rolename' => 'editingteacher',
 398              ],
 399              'Teacher actionsmenu tag with default options (check Show more is not there)' => [
 400                  'templatecontent' => 'Some ##actionsmenu## tag',
 401                  'expected' => '|^Some((?!Show more).)*tag$|',
 402                  'rolename' => 'editingteacher',
 403              ],
 404              'Teacher actionsmenu tag with show more enabled' => [
 405                  'templatecontent' => 'Some ##actionsmenu## tag',
 406                  'expected' => '|Some .*view.*{cmid}.*rid.*{entryid}.*Show more.* .*Edit.* .*Delete.* tag|',
 407                  'rolename' => 'editingteacher',
 408                  'enableexport' => false,
 409                  'approved' => false,
 410                  'enablecomments' => false,
 411                  'enableratings' => false,
 412                  'options' => ['showmore' => true],
 413              ],
 414              'Teacher actionsmenu tag with export enabled' => [
 415                  'templatecontent' => 'Some ##actionsmenu## tag',
 416                  'expected' => '|Some .*Edit.* .*Delete.* .*portfolio/add.* tag|',
 417                  'rolename' => 'editingteacher',
 418                  'enableexport' => true,
 419              ],
 420              'Teacher actionsmenu tag with approved enabled' => [
 421                  'templatecontent' => 'Some ##actionsmenu## tag',
 422                  'expected' => '|Some .*Edit.* .*Delete.* .*disapprove.*{entryid}.*sesskey.*Undo approval.* tag|',
 423                  'rolename' => 'editingteacher',
 424                  'enableexport' => false,
 425                  'approved' => true,
 426              ],
 427              'Teacher actionsmenu tag with export, approved and showmore enabled' => [
 428                  'templatecontent' => 'Some ##actionsmenu## tag',
 429                  'expected' => '|Some .*Show more.* .*Edit.* .*Delete.* .*Undo approval.* .*Export to portfolio.* tag|',
 430                  'rolename' => 'editingteacher',
 431                  'enableexport' => true,
 432                  'approved' => true,
 433                  'enablecomments' => false,
 434                  'enableratings' => false,
 435                  'options' => ['showmore' => true],
 436              ],
 437              // Student scenarios.
 438              'Student id tag' => [
 439                  'templatecontent' => 'Some ##id## tag',
 440                  'expected' => '|Some {entryid} tag|',
 441                  'rolename' => 'student',
 442              ],
 443              'Student delete tag' => [
 444                  'templatecontent' => 'Some ##delete## tag',
 445                  'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 446                  'rolename' => 'student',
 447              ],
 448              'Student delete tag on other author entry' => [
 449                  'templatecontent' => 'Some ##delete## tag',
 450                  'expected' => '|Some  tag|',
 451                  'rolename' => 'student',
 452                  'enableexport' => false,
 453                  'approved' => true,
 454                  'enablecomments' => false,
 455                  'enableratings' => false,
 456                  'options' => [],
 457                  'otherauthor' => true,
 458              ],
 459              'Student edit tag' => [
 460                  'templatecontent' => 'Some ##edit## tag',
 461                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
 462                  'rolename' => 'student',
 463              ],
 464              'Student edit tag on other author entry' => [
 465                  'templatecontent' => 'Some ##edit## tag',
 466                  'expected' => '|Some  tag|',
 467                  'rolename' => 'student',
 468                  'enableexport' => false,
 469                  'approved' => true,
 470                  'enablecomments' => false,
 471                  'enableratings' => false,
 472                  'options' => [],
 473                  'otherauthor' => true,
 474              ],
 475              'Student more tag' => [
 476                  'templatecontent' => 'Some ##more## tag',
 477                  'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
 478                  'rolename' => 'student',
 479                  'enableexport' => false,
 480                  'approved' => true,
 481                  'enablecomments' => false,
 482                  'enableratings' => false,
 483                  'options' => ['showmore' => true],
 484              ],
 485              'Student more tag with showmore set to false' => [
 486                  'templatecontent' => 'Some ##more## tag',
 487                  'expected' => '|Some  tag|',
 488                  'rolename' => 'student',
 489                  'enableexport' => false,
 490                  'approved' => true,
 491                  'enablecomments' => false,
 492                  'enableratings' => false,
 493                  'options' => ['showmore' => false],
 494              ],
 495              'Student moreurl tag' => [
 496                  'templatecontent' => 'Some ##moreurl## tag',
 497                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 498                  'rolename' => 'student',
 499                  'enableexport' => false,
 500                  'approved' => true,
 501                  'enablecomments' => false,
 502                  'enableratings' => false,
 503                  'options' => ['showmore' => true],
 504              ],
 505              'Student moreurl tag with showmore set to false' => [
 506                  'templatecontent' => 'Some ##moreurl## tag',
 507                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 508                  'rolename' => 'student',
 509                  'enableexport' => false,
 510                  'approved' => true,
 511                  'enablecomments' => false,
 512                  'enableratings' => false,
 513                  'options' => ['showmore' => false],
 514              ],
 515              'Student delcheck tag' => [
 516                  'templatecontent' => 'Some ##delcheck## tag',
 517                  'expected' => '|Some  tag|',
 518                  'rolename' => 'student',
 519              ],
 520              'Student user tag' => [
 521                  'templatecontent' => 'Some ##user## tag',
 522                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
 523                  'rolename' => 'student',
 524              ],
 525              'Student userpicture tag' => [
 526                  'templatecontent' => 'Some ##userpicture## tag',
 527                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
 528                  'rolename' => 'student',
 529              ],
 530              'Student export tag' => [
 531                  'templatecontent' => 'Some ##export## tag',
 532                  'expected' => '|Some .*portfolio/add.* tag|',
 533                  'rolename' => 'student',
 534                  'enableexport' => true,
 535              ],
 536              'Student export tag not configured' => [
 537                  'templatecontent' => 'Some ##export## tag',
 538                  'expected' => '|Some  tag|',
 539                  'rolename' => 'student',
 540                  'enableexport' => false,
 541              ],
 542              'Student export tag on other user entry' => [
 543                  'templatecontent' => 'Some ##export## tag',
 544                  'expected' => '|Some  tag|',
 545                  'rolename' => 'student',
 546                  'enableexport' => false,
 547                  'approved' => true,
 548                  'enablecomments' => false,
 549                  'enableratings' => false,
 550                  'options' => [],
 551                  'otherauthor' => true,
 552              ],
 553              'Student timeadded tag' => [
 554                  'templatecontent' => 'Some ##timeadded## tag',
 555                  'expected' => '|Some <span.*>{timeadded}</span> tag|',
 556                  'rolename' => 'student',
 557              ],
 558              'Student timemodified tag' => [
 559                  'templatecontent' => 'Some ##timemodified## tag',
 560                  'expected' => '|Some <span.*>{timemodified}</span> tag|',
 561                  'rolename' => 'student',
 562              ],
 563              'Student approve tag approved entry' => [
 564                  'templatecontent' => 'Some ##approve## tag',
 565                  'expected' => '|Some  tag|',
 566                  'rolename' => 'student',
 567                  'enableexport' => false,
 568                  'approved' => true,
 569              ],
 570              'Student approve tag disapproved entry' => [
 571                  'templatecontent' => 'Some ##approve## tag',
 572                  'expected' => '|Some  tag|',
 573                  'rolename' => 'student',
 574                  'enableexport' => false,
 575                  'approved' => false,
 576              ],
 577              'Student disapprove tag approved entry' => [
 578                  'templatecontent' => 'Some ##disapprove## tag',
 579                  'expected' => '|Some  tag|',
 580                  'rolename' => 'student',
 581                  'enableexport' => false,
 582                  'approved' => true,
 583              ],
 584              'Student disapprove tag disapproved entry' => [
 585                  'templatecontent' => 'Some ##disapprove## tag',
 586                  'expected' => '|Some  tag|',
 587                  'rolename' => 'student',
 588                  'enableexport' => false,
 589                  'approved' => false,
 590              ],
 591              'Student approvalstatus tag approved entry' => [
 592                  'templatecontent' => 'Some ##approvalstatus## tag',
 593                  'expected' => '|Some  tag|',
 594                  'rolename' => 'student',
 595                  'enableexport' => false,
 596                  'approved' => true,
 597              ],
 598              'Student approvalstatus tag disapproved entry' => [
 599                  'templatecontent' => 'Some ##approvalstatus## tag',
 600                  'expected' => '|Some .*Pending approval.* tag|',
 601                  'rolename' => 'student',
 602                  'enableexport' => false,
 603                  'approved' => false,
 604              ],
 605              'Student approvalstatusclass tag approved entry' => [
 606                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 607                  'expected' => '|Some approved tag|',
 608                  'rolename' => 'student',
 609                  'enableexport' => false,
 610                  'approved' => true,
 611              ],
 612              'Student approvalstatusclass tag disapproved entry' => [
 613                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 614                  'expected' => '|Some notapproved tag|',
 615                  'rolename' => 'student',
 616                  'enableexport' => false,
 617                  'approved' => false,
 618              ],
 619              'Student tags tag' => [
 620                  'templatecontent' => 'Some ##tags## tag',
 621                  'expected' => '|Some .*Cats.* tag|',
 622                  'rolename' => 'student',
 623              ],
 624              'Student field name tag' => [
 625                  'templatecontent' => 'Some [[myfield]] tag',
 626                  'expected' => '|Some .*Example entry.* tag|',
 627                  'rolename' => 'student',
 628              ],
 629              'Student field#id name tag' => [
 630                  'templatecontent' => 'Some [[myfield#id]] tag',
 631                  'expected' => '|Some {fieldid} tag|',
 632                  'rolename' => 'student',
 633              ],
 634              'Student comments name tag with comments enabled' => [
 635                  'templatecontent' => 'Some ##comments## tag',
 636                  'expected' => '|Some .*Comments.* tag|',
 637                  'rolename' => 'student',
 638                  'enableexport' => false,
 639                  'approved' => true,
 640                  'enablecomments' => true,
 641              ],
 642              'Student comments name tag with comments disabled' => [
 643                  'templatecontent' => 'Some ##comments## tag',
 644                  'expected' => '|Some  tag|',
 645                  'rolename' => 'student',
 646                  'enableexport' => false,
 647                  'approved' => true,
 648                  'enablecomments' => false,
 649              ],
 650              'Student comment forced with comments enables' => [
 651                  'templatecontent' => 'No tags',
 652                  'expected' => '|No tags.*Comments.*|',
 653                  'rolename' => 'student',
 654                  'enableexport' => false,
 655                  'approved' => true,
 656                  'enablecomments' => true,
 657                  'enableratings' => false,
 658                  'options' => ['comments' => true]
 659              ],
 660              'Student comment forced without comments enables' => [
 661                  'templatecontent' => 'No tags',
 662                  'expected' => '|^No tags$|',
 663                  'rolename' => 'student',
 664                  'enableexport' => false,
 665                  'approved' => true,
 666                  'enablecomments' => false,
 667                  'enableratings' => false,
 668                  'options' => ['comments' => true]
 669              ],
 670              'Student adding ratings without ratings configured' => [
 671                  'templatecontent' => 'No tags',
 672                  'expected' => '|^No tags$|',
 673                  'rolename' => 'student',
 674                  'enableexport' => false,
 675                  'approved' => true,
 676                  'enablecomments' => false,
 677                  'enableratings' => false,
 678                  'options' => ['ratings' => true]
 679              ],
 680              'Student adding ratings with ratings configured' => [
 681                  'templatecontent' => 'No tags',
 682                  'expected' => '|^No tags$|',
 683                  'rolename' => 'student',
 684                  'enableexport' => false,
 685                  'approved' => true,
 686                  'enablecomments' => false,
 687                  'enableratings' => true,
 688                  'options' => ['ratings' => true]
 689              ],
 690              'Student actionsmenu tag with default options' => [
 691                  'templatecontent' => 'Some ##actionsmenu## tag',
 692                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 693                  'rolename' => 'student',
 694              ],
 695              'Student actionsmenu tag with default options (check Show more is not there)' => [
 696                  'templatecontent' => 'Some ##actionsmenu## tag',
 697                  'expected' => '|^Some((?!Show more).)*tag$|',
 698                  'rolename' => 'student',
 699              ],
 700              'Student actionsmenu tag with show more enabled' => [
 701                  'templatecontent' => 'Some ##actionsmenu## tag',
 702                  'expected' => '|Some .*view.*{cmid}.*rid.*{entryid}.*Show more.* .*Edit.* .*Delete.* tag|',
 703                  'rolename' => 'student',
 704                  'enableexport' => false,
 705                  'approved' => false,
 706                  'enablecomments' => false,
 707                  'enableratings' => false,
 708                  'options' => ['showmore' => true],
 709              ],
 710              'Student actionsmenu tag with export enabled' => [
 711                  'templatecontent' => 'Some ##actionsmenu## tag',
 712                  'expected' => '|Some .*Edit.* .*Delete.* .*portfolio/add.* tag|',
 713                  'rolename' => 'student',
 714                  'enableexport' => true,
 715              ],
 716              'Student actionsmenu tag with approved enabled' => [
 717                  'templatecontent' => 'Some ##actionsmenu## tag',
 718                  'expected' => '|^Some((?!Approve).)*tag$|',
 719                  'rolename' => 'student',
 720                  'enableexport' => false,
 721                  'approved' => true,
 722              ],
 723              'Student actionsmenu tag with export, approved and showmore enabled' => [
 724                  'templatecontent' => 'Some ##actionsmenu## tag',
 725                  'expected' => '|Some .*Show more.* .*Edit.* .*Delete.* .*Export to portfolio.* tag|',
 726                  'rolename' => 'student',
 727                  'enableexport' => true,
 728                  'approved' => true,
 729                  'enablecomments' => false,
 730                  'enableratings' => false,
 731                  'options' => ['showmore' => true],
 732              ],
 733          ];
 734      }
 735  
 736      /**
 737       * Create all the necessary data to enable portfolio export in mod_data
 738       *
 739       * @param stdClass $user the current user record.
 740       */
 741      protected function enable_portfolio(stdClass $user) {
 742          global $DB;
 743          set_config('enableportfolios', 1);
 744  
 745          $plugin = 'download';
 746          $name = 'Download';
 747  
 748          $portfolioinstance = (object) [
 749              'plugin' => $plugin,
 750              'name' => $name,
 751              'visible' => 1
 752          ];
 753          $portfolioinstance->id = $DB->insert_record('portfolio_instance', $portfolioinstance);
 754          $userinstance = (object) [
 755              'instance' => $portfolioinstance->id,
 756              'userid' => $user->id,
 757              'name' => 'visible',
 758              'value' => 1
 759          ];
 760          $DB->insert_record('portfolio_instance_user', $userinstance);
 761  
 762          $DB->insert_record('portfolio_log', [
 763              'portfolio' => $portfolioinstance->id,
 764              'userid' => $user->id,
 765              'caller_class' => 'data_portfolio_caller',
 766              'caller_component' => 'mod_data',
 767              'time' => time(),
 768          ]);
 769      }
 770  
 771      /**
 772       * Enable the ratings on the database entries.
 773       *
 774       * @param context_module $context the activity context
 775       * @param stdClass $activity the activity record
 776       * @param array $entries database entries
 777       * @param stdClass $user the current user record
 778       * @return stdClass the entries with the rating attribute
 779       */
 780      protected function enable_ratings(context_module $context, stdClass $activity, array $entries, stdClass $user) {
 781          global $CFG;
 782          $ratingoptions = (object)[
 783              'context' => $context,
 784              'component' => 'mod_data',
 785              'ratingarea' => 'entry',
 786              'items' => $entries,
 787              'aggregate' => RATING_AGGREGATE_AVERAGE,
 788              'scaleid' => $activity->scale,
 789              'userid' => $user->id,
 790              'returnurl' => $CFG->wwwroot . '/mod/data/view.php',
 791              'assesstimestart' => $activity->assesstimestart,
 792              'assesstimefinish' => $activity->assesstimefinish,
 793          ];
 794          $rm = new rating_manager();
 795          return $rm->get_ratings($ratingoptions);
 796      }
 797  
 798      /**
 799       * Test parse add entry template parsing.
 800       *
 801       * @covers ::parse_add_entry
 802       * @dataProvider parse_add_entry_provider
 803       * @param string $templatecontent the template string
 804       * @param string $expected expected output
 805       * @param bool $newentry if it is a new entry or editing and existing one
 806       */
 807      public function test_parse_add_entry(
 808          string $templatecontent,
 809          string $expected,
 810          bool $newentry = false
 811      ) {
 812          global $DB, $PAGE;
 813          // Comments, tags, approval, user role.
 814          $this->resetAfterTest();
 815  
 816          $params = ['approval' => true];
 817  
 818          $course = $this->getDataGenerator()->create_course();
 819          $params['course'] = $course;
 820          $activity = $this->getDataGenerator()->create_module('data', $params);
 821          $author = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 822  
 823          // Generate an entry.
 824          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 825          $fieldrecord = (object)[
 826              'name' => 'myfield',
 827              'type' => 'text',
 828          ];
 829          $field = $generator->create_field($fieldrecord, $activity);
 830  
 831          if ($newentry) {
 832              $entryid = null;
 833              $entry = null;
 834          } else {
 835              $entryid = $generator->create_entry(
 836                  $activity,
 837                  [$field->field->id => 'Example entry'],
 838                  0,
 839                  ['Cats', 'Dogs']
 840              );
 841              $entry = (object)[
 842                  'd' => $activity->id,
 843                  'rid' => $entryid,
 844                  "field_{$field->field->id}" => "New value",
 845              ];
 846          }
 847  
 848          $manager = manager::create_from_instance($activity);
 849  
 850          // Some cooked variables for the regular expression.
 851          $replace = [
 852              '{fieldid}' => $field->field->id,
 853          ];
 854  
 855          $processdata = (object)[
 856              'generalnotifications' => ['GENERAL'],
 857              'fieldnotifications' => [$field->field->name => ['FIELD']],
 858          ];
 859  
 860          $parser = new template($manager, $templatecontent);
 861          $result = $parser->parse_add_entry($processdata, $entryid, $entry);
 862  
 863          // We don't want line breaks for the validations.
 864          $result = str_replace("\n", '', $result);
 865          $regexp = str_replace(array_keys($replace), array_values($replace), $expected);
 866          $this->assertMatchesRegularExpression($regexp, $result);
 867      }
 868  
 869      /**
 870       * Data provider for test_parse_add_entry().
 871       *
 872       * @return array of scenarios
 873       */
 874      public function parse_add_entry_provider(): array {
 875          return [
 876              // Editing an entry.
 877              'Teacher editing entry tags tag' => [
 878                  'templatecontent' => 'Some ##tags## tag',
 879                  'expected' => '|GENERAL.*Some .*select .*tags.*Cats.* tag|',
 880                  'newentry' => false,
 881              ],
 882              'Teacher editing entry field name tag' => [
 883                  'templatecontent' => 'Some [[myfield]] tag',
 884                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* tag|',
 885                  'newentry' => false,
 886              ],
 887              'Teacher editing entry field#id tag' => [
 888                  'templatecontent' => 'Some [[myfield#id]] tag',
 889                  'expected' => '|GENERAL.*Some field_{fieldid} tag|',
 890                  'newentry' => false,
 891              ],
 892              // New entry.
 893              'Teacher new entry tags tag' => [
 894                  'templatecontent' => 'Some ##tags## tag',
 895                  'expected' => '|GENERAL.*Some .*select .*tags\[\].* tag|',
 896                  'newentry' => true,
 897              ],
 898              'Teacher new entry field name tag' => [
 899                  'templatecontent' => 'Some [[myfield]] tag',
 900                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*value="".* tag|',
 901                  'newentry' => true,
 902              ],
 903              'Teacher new entry field#id name tag' => [
 904                  'templatecontent' => 'Some [[myfield#id]] tag',
 905                  'expected' => '|GENERAL.*Some field_{fieldid} tag|',
 906                  'newentry' => true,
 907              ],
 908          ];
 909      }
 910  }