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] [Versions 39 and 310]

   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   * Topics course format related unit tests.
  19   *
  20   * @package    format_topics
  21   * @copyright  2015 Marina Glancy
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  require_once($CFG->dirroot . '/course/lib.php');
  29  
  30  /**
  31   * Topics course format related unit tests.
  32   *
  33   * @package    format_topics
  34   * @copyright  2015 Marina Glancy
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class format_topics_testcase extends advanced_testcase {
  38  
  39      /**
  40       * Tests for format_topics::get_section_name method with default section names.
  41       *
  42       * @return void
  43       */
  44      public function test_get_section_name() {
  45          global $DB;
  46          $this->resetAfterTest(true);
  47  
  48          // Generate a course with 5 sections.
  49          $generator = $this->getDataGenerator();
  50          $numsections = 5;
  51          $course = $generator->create_course(['numsections' => $numsections, 'format' => 'topics'],
  52              ['createsections' => true]);
  53  
  54          // Get section names for course.
  55          $coursesections = $DB->get_records('course_sections', ['course' => $course->id]);
  56  
  57          // Test get_section_name with default section names.
  58          $courseformat = course_get_format($course);
  59          foreach ($coursesections as $section) {
  60              // Assert that with unmodified section names, get_section_name returns the same result as get_default_section_name.
  61              $this->assertEquals($courseformat->get_default_section_name($section), $courseformat->get_section_name($section));
  62          }
  63      }
  64  
  65      /**
  66       * Tests for format_topics::get_section_name method with modified section names.
  67       *
  68       * @return void
  69       */
  70      public function test_get_section_name_customised() {
  71          global $DB;
  72          $this->resetAfterTest(true);
  73  
  74          // Generate a course with 5 sections.
  75          $generator = $this->getDataGenerator();
  76          $numsections = 5;
  77          $course = $generator->create_course(['numsections' => $numsections, 'format' => 'topics'],
  78              ['createsections' => true]);
  79  
  80          // Get section names for course.
  81          $coursesections = $DB->get_records('course_sections', ['course' => $course->id]);
  82  
  83          // Modify section names.
  84          $customname = "Custom Section";
  85          foreach ($coursesections as $section) {
  86              $section->name = "$customname $section->section";
  87              $DB->update_record('course_sections', $section);
  88          }
  89  
  90          // Requery updated section names then test get_section_name.
  91          $coursesections = $DB->get_records('course_sections', ['course' => $course->id]);
  92          $courseformat = course_get_format($course);
  93          foreach ($coursesections as $section) {
  94              // Assert that with modified section names, get_section_name returns the modified section name.
  95              $this->assertEquals($section->name, $courseformat->get_section_name($section));
  96          }
  97      }
  98  
  99      /**
 100       * Tests for format_topics::get_default_section_name.
 101       *
 102       * @return void
 103       */
 104      public function test_get_default_section_name() {
 105          global $DB;
 106          $this->resetAfterTest(true);
 107  
 108          // Generate a course with 5 sections.
 109          $generator = $this->getDataGenerator();
 110          $numsections = 5;
 111          $course = $generator->create_course(['numsections' => $numsections, 'format' => 'topics'],
 112              ['createsections' => true]);
 113  
 114          // Get section names for course.
 115          $coursesections = $DB->get_records('course_sections', ['course' => $course->id]);
 116  
 117          // Test get_default_section_name with default section names.
 118          $courseformat = course_get_format($course);
 119          foreach ($coursesections as $section) {
 120              if ($section->section == 0) {
 121                  $sectionname = get_string('section0name', 'format_topics');
 122                  $this->assertEquals($sectionname, $courseformat->get_default_section_name($section));
 123              } else {
 124                  $sectionname = get_string('sectionname', 'format_topics') . ' ' . $section->section;
 125                  $this->assertEquals($sectionname, $courseformat->get_default_section_name($section));
 126              }
 127          }
 128      }
 129  
 130      /**
 131       * Test web service updating section name.
 132       *
 133       * @return void
 134       */
 135      public function test_update_inplace_editable() {
 136          global $CFG, $DB, $PAGE;
 137          require_once($CFG->dirroot . '/lib/external/externallib.php');
 138  
 139          $this->resetAfterTest();
 140          $user = $this->getDataGenerator()->create_user();
 141          $this->setUser($user);
 142          $course = $this->getDataGenerator()->create_course(['numsections' => 5, 'format' => 'topics'],
 143              ['createsections' => true]);
 144          $section = $DB->get_record('course_sections', ['course' => $course->id, 'section' => 2]);
 145  
 146          // Call webservice without necessary permissions.
 147          try {
 148              core_external::update_inplace_editable('format_topics', 'sectionname', $section->id, 'New section name');
 149              $this->fail('Exception expected');
 150          } catch (moodle_exception $e) {
 151              $this->assertEquals('Course or activity not accessible. (Not enrolled)',
 152                      $e->getMessage());
 153          }
 154  
 155          // Change to teacher and make sure that section name can be updated using web service update_inplace_editable().
 156          $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
 157          $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
 158  
 159          $res = core_external::update_inplace_editable('format_topics', 'sectionname', $section->id, 'New section name');
 160          $res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
 161          $this->assertEquals('New section name', $res['value']);
 162          $this->assertEquals('New section name', $DB->get_field('course_sections', 'name', ['id' => $section->id]));
 163      }
 164  
 165      /**
 166       * Test callback updating section name.
 167       *
 168       * @return void
 169       */
 170      public function test_inplace_editable() {
 171          global $DB, $PAGE;
 172  
 173          $this->resetAfterTest();
 174          $user = $this->getDataGenerator()->create_user();
 175          $course = $this->getDataGenerator()->create_course(['numsections' => 5, 'format' => 'topics'],
 176              ['createsections' => true]);
 177          $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
 178          $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
 179          $this->setUser($user);
 180  
 181          $section = $DB->get_record('course_sections', ['course' => $course->id, 'section' => 2]);
 182  
 183          // Call callback format_topics_inplace_editable() directly.
 184          $tmpl = component_callback('format_topics', 'inplace_editable', ['sectionname', $section->id, 'Rename me again']);
 185          $this->assertInstanceOf('core\output\inplace_editable', $tmpl);
 186          $res = $tmpl->export_for_template($PAGE->get_renderer('core'));
 187          $this->assertEquals('Rename me again', $res['value']);
 188          $this->assertEquals('Rename me again', $DB->get_field('course_sections', 'name', ['id' => $section->id]));
 189  
 190          // Try updating using callback from mismatching course format.
 191          try {
 192              component_callback('format_weeks', 'inplace_editable', ['sectionname', $section->id, 'New name']);
 193              $this->fail('Exception expected');
 194          } catch (moodle_exception $e) {
 195              $this->assertEquals(1, preg_match('/^Can\'t find data record in database/', $e->getMessage()));
 196          }
 197      }
 198  
 199      /**
 200       * Test get_default_course_enddate.
 201       *
 202       * @return void
 203       */
 204      public function test_default_course_enddate() {
 205          global $CFG, $DB;
 206  
 207          $this->resetAfterTest(true);
 208  
 209          require_once($CFG->dirroot . '/course/tests/fixtures/testable_course_edit_form.php');
 210  
 211          $this->setTimezone('UTC');
 212  
 213          $params = ['format' => 'topics', 'numsections' => 5, 'startdate' => 1445644800];
 214          $course = $this->getDataGenerator()->create_course($params);
 215          $category = $DB->get_record('course_categories', ['id' => $course->category]);
 216  
 217          $args = [
 218              'course' => $course,
 219              'category' => $category,
 220              'editoroptions' => [
 221                  'context' => context_course::instance($course->id),
 222                  'subdirs' => 0
 223              ],
 224              'returnto' => new moodle_url('/'),
 225              'returnurl' => new moodle_url('/'),
 226          ];
 227  
 228          $courseform = new testable_course_edit_form(null, $args);
 229          $courseform->definition_after_data();
 230  
 231          $enddate = $params['startdate'] + get_config('moodlecourse', 'courseduration');
 232  
 233          $weeksformat = course_get_format($course->id);
 234          $this->assertEquals($enddate, $weeksformat->get_default_course_enddate($courseform->get_quick_form()));
 235  
 236      }
 237  
 238      /**
 239       * Test for get_view_url() to ensure that the url is only given for the correct cases.
 240       *
 241       * @return void
 242       */
 243      public function test_get_view_url() {
 244          global $CFG;
 245          $this->resetAfterTest();
 246  
 247          $linkcoursesections = $CFG->linkcoursesections;
 248  
 249          // Generate a course with two sections (0 and 1) and two modules.
 250          $generator = $this->getDataGenerator();
 251          $course1 = $generator->create_course(['format' => 'topics']);
 252          course_create_sections_if_missing($course1, [0, 1]);
 253  
 254          $data = (object)['id' => $course1->id];
 255          $format = course_get_format($course1);
 256          $format->update_course_format_options($data);
 257  
 258          // In page.
 259          $CFG->linkcoursesections = 0;
 260          $this->assertNotEmpty($format->get_view_url(null));
 261          $this->assertNotEmpty($format->get_view_url(0));
 262          $this->assertNotEmpty($format->get_view_url(1));
 263          $CFG->linkcoursesections = 1;
 264          $this->assertNotEmpty($format->get_view_url(null));
 265          $this->assertNotEmpty($format->get_view_url(0));
 266          $this->assertNotEmpty($format->get_view_url(1));
 267  
 268          // Navigation.
 269          $CFG->linkcoursesections = 0;
 270          $this->assertNull($format->get_view_url(1, ['navigation' => 1]));
 271          $this->assertNull($format->get_view_url(0, ['navigation' => 1]));
 272          $CFG->linkcoursesections = 1;
 273          $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1]));
 274          $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1]));
 275      }
 276  }