| 1 | efrain | 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 core_courseformat\local;
 | 
        
           |  |  | 18 |   | 
        
           |  |  | 19 | use stdClass;
 | 
        
           |  |  | 20 |   | 
        
           |  |  | 21 | /**
 | 
        
           |  |  | 22 |  * Section format actions class tests.
 | 
        
           |  |  | 23 |  *
 | 
        
           |  |  | 24 |  * @package    core_courseformat
 | 
        
           |  |  | 25 |  * @copyright  2023 Ferran Recio <ferran@moodle.com>
 | 
        
           |  |  | 26 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           | 1441 | ariadna | 27 |  * @coversDefaultClass \core_courseformat\local\sectionactions
 | 
        
           | 1 | efrain | 28 |  */
 | 
        
           | 1441 | ariadna | 29 | final class sectionactions_test extends \advanced_testcase {
 | 
        
           | 1 | efrain | 30 |     /**
 | 
        
           |  |  | 31 |      * Setup to ensure that fixtures are loaded.
 | 
        
           |  |  | 32 |      */
 | 
        
           |  |  | 33 |     public static function setUpBeforeClass(): void {
 | 
        
           |  |  | 34 |         global $CFG;
 | 
        
           |  |  | 35 |         require_once($CFG->dirroot . '/course/lib.php');
 | 
        
           | 1441 | ariadna | 36 |         parent::setUpBeforeClass();
 | 
        
           | 1 | efrain | 37 |     }
 | 
        
           |  |  | 38 |   | 
        
           |  |  | 39 |     /**
 | 
        
           |  |  | 40 |      * Test for create_delegated method.
 | 
        
           |  |  | 41 |      * @covers ::create_delegated
 | 
        
           |  |  | 42 |      * @dataProvider create_delegated_provider
 | 
        
           |  |  | 43 |      * @param string $component the name of the plugin
 | 
        
           |  |  | 44 |      * @param int|null $itemid the id of the delegated section
 | 
        
           |  |  | 45 |      * @param stdClass|null $fields the fields to set on the section
 | 
        
           |  |  | 46 |      */
 | 
        
           |  |  | 47 |     public function test_create_delegated(string $component, ?int $itemid, ?stdClass $fields): void {
 | 
        
           |  |  | 48 |         global $DB;
 | 
        
           |  |  | 49 |         $this->resetAfterTest();
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 |         $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 1]);
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 54 |         $section = $sectionactions->create_delegated($component, $itemid, $fields);
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |         $this->assertEquals($component, $section->component);
 | 
        
           |  |  | 57 |         $this->assertEquals($itemid, $section->itemid);
 | 
        
           |  |  | 58 |         if (!empty($fields)) {
 | 
        
           |  |  | 59 |             foreach ($fields as $field => $value) {
 | 
        
           |  |  | 60 |                 $this->assertEquals($value, $section->$field);
 | 
        
           |  |  | 61 |             }
 | 
        
           |  |  | 62 |         }
 | 
        
           |  |  | 63 |     }
 | 
        
           |  |  | 64 |   | 
        
           |  |  | 65 |     /**
 | 
        
           |  |  | 66 |      * Data provider for test_create_delegated.
 | 
        
           |  |  | 67 |      * @return array
 | 
        
           |  |  | 68 |      */
 | 
        
           |  |  | 69 |     public static function create_delegated_provider(): array {
 | 
        
           |  |  | 70 |         return [
 | 
        
           |  |  | 71 |             'component with no itemid or fields' => [
 | 
        
           |  |  | 72 |                 'mod_assign',
 | 
        
           |  |  | 73 |                 null,
 | 
        
           |  |  | 74 |                 null,
 | 
        
           |  |  | 75 |             ],
 | 
        
           |  |  | 76 |             'component with itemid but no fields' => [
 | 
        
           |  |  | 77 |                 'mod_assign',
 | 
        
           |  |  | 78 |                 1,
 | 
        
           |  |  | 79 |                 null,
 | 
        
           |  |  | 80 |             ],
 | 
        
           |  |  | 81 |             'component with itemid and empty fields' => [
 | 
        
           |  |  | 82 |                 'mod_assign',
 | 
        
           |  |  | 83 |                 1,
 | 
        
           |  |  | 84 |                 new stdClass(),
 | 
        
           |  |  | 85 |             ],
 | 
        
           |  |  | 86 |             'component with itemid and name field' => [
 | 
        
           |  |  | 87 |                 'mod_assign',
 | 
        
           |  |  | 88 |                 1,
 | 
        
           |  |  | 89 |                 (object) ['name' => 'new name'],
 | 
        
           |  |  | 90 |             ],
 | 
        
           |  |  | 91 |             'component with no itemid but name field' => [
 | 
        
           |  |  | 92 |                 'mod_assign',
 | 
        
           |  |  | 93 |                 null,
 | 
        
           |  |  | 94 |                 (object) ['name' => 'new name'],
 | 
        
           |  |  | 95 |             ],
 | 
        
           |  |  | 96 |             'component with itemid and summary' => [
 | 
        
           |  |  | 97 |                 'mod_assign',
 | 
        
           |  |  | 98 |                 1,
 | 
        
           |  |  | 99 |                 (object) ['summary' => 'summary'],
 | 
        
           |  |  | 100 |             ],
 | 
        
           |  |  | 101 |             'component with itemid and summary, summaryformat ' => [
 | 
        
           |  |  | 102 |                 'mod_assign',
 | 
        
           |  |  | 103 |                 1,
 | 
        
           |  |  | 104 |                 (object) ['summary' => 'summary', 'summaryformat' => 1],
 | 
        
           |  |  | 105 |             ],
 | 
        
           |  |  | 106 |             'component with itemid and section number' => [
 | 
        
           |  |  | 107 |                 'mod_assign',
 | 
        
           |  |  | 108 |                 1,
 | 
        
           |  |  | 109 |                 (object) ['section' => 2],
 | 
        
           |  |  | 110 |             ],
 | 
        
           |  |  | 111 |             'component with itemid and visible 1' => [
 | 
        
           |  |  | 112 |                 'mod_assign',
 | 
        
           |  |  | 113 |                 1,
 | 
        
           |  |  | 114 |                 (object) ['visible' => 1],
 | 
        
           |  |  | 115 |             ],
 | 
        
           |  |  | 116 |             'component with itemid and visible 0' => [
 | 
        
           |  |  | 117 |                 'mod_assign',
 | 
        
           |  |  | 118 |                 1,
 | 
        
           |  |  | 119 |                 (object) ['visible' => 0],
 | 
        
           |  |  | 120 |             ],
 | 
        
           |  |  | 121 |         ];
 | 
        
           |  |  | 122 |     }
 | 
        
           |  |  | 123 |   | 
        
           |  |  | 124 |     /**
 | 
        
           |  |  | 125 |      * Test for create method.
 | 
        
           |  |  | 126 |      * @covers ::create
 | 
        
           |  |  | 127 |      * @dataProvider create_provider
 | 
        
           |  |  | 128 |      * @param int $sectionnum the name of the plugin
 | 
        
           |  |  | 129 |      * @param bool $skip if the validation should be skipped
 | 
        
           |  |  | 130 |      * @param bool $expectexception if the method should throw an exception
 | 
        
           |  |  | 131 |      * @param int $expected the expected section number
 | 
        
           |  |  | 132 |      */
 | 
        
           |  |  | 133 |     public function test_create(int $sectionnum, bool $skip, bool $expectexception, int $expected): void {
 | 
        
           |  |  | 134 |         global $DB;
 | 
        
           |  |  | 135 |         $this->resetAfterTest();
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 |         $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 1]);
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |         if ($expectexception) {
 | 
        
           |  |  | 142 |             $this->expectException(\dml_write_exception::class);
 | 
        
           |  |  | 143 |         }
 | 
        
           |  |  | 144 |         $section = $sectionactions->create($sectionnum, $skip);
 | 
        
           |  |  | 145 |   | 
        
           |  |  | 146 |         $this->assertEquals($expected, $section->section);
 | 
        
           |  |  | 147 |     }
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |     /**
 | 
        
           |  |  | 150 |      * Data provider for test_create_delegated.
 | 
        
           |  |  | 151 |      * @return array
 | 
        
           |  |  | 152 |      */
 | 
        
           |  |  | 153 |     public static function create_provider(): array {
 | 
        
           |  |  | 154 |         return [
 | 
        
           |  |  | 155 |             'section 1' => [
 | 
        
           |  |  | 156 |                 'sectionnum' => 1,
 | 
        
           |  |  | 157 |                 'skip' => false,
 | 
        
           |  |  | 158 |                 'expectexception' => false,
 | 
        
           |  |  | 159 |                 'expected' => 1,
 | 
        
           |  |  | 160 |             ],
 | 
        
           |  |  | 161 |             'section 2' => [
 | 
        
           |  |  | 162 |                 'sectionnum' => 2,
 | 
        
           |  |  | 163 |                 'skip' => false,
 | 
        
           |  |  | 164 |                 'expectexception' => false,
 | 
        
           |  |  | 165 |                 'expected' => 2,
 | 
        
           |  |  | 166 |             ],
 | 
        
           |  |  | 167 |             'section 3' => [
 | 
        
           |  |  | 168 |                 'sectionnum' => 3,
 | 
        
           |  |  | 169 |                 'skip' => false,
 | 
        
           |  |  | 170 |                 'expectexception' => false,
 | 
        
           |  |  | 171 |                 'expected' => 2,
 | 
        
           |  |  | 172 |             ],
 | 
        
           |  |  | 173 |             'section 4' => [
 | 
        
           |  |  | 174 |                 'sectionnum' => 4,
 | 
        
           |  |  | 175 |                 'skip' => false,
 | 
        
           |  |  | 176 |                 'expectexception' => false,
 | 
        
           |  |  | 177 |                 'expected' => 2,
 | 
        
           |  |  | 178 |             ],
 | 
        
           |  |  | 179 |             'section 1 with exception' => [
 | 
        
           |  |  | 180 |                 'sectionnum' => 1,
 | 
        
           |  |  | 181 |                 'skip' => true,
 | 
        
           |  |  | 182 |                 'expectexception' => true,
 | 
        
           |  |  | 183 |                 'expected' => 0,
 | 
        
           |  |  | 184 |             ],
 | 
        
           |  |  | 185 |             'section 2 with skip validation' => [
 | 
        
           |  |  | 186 |                 'sectionnum' => 2,
 | 
        
           |  |  | 187 |                 'skip' => true,
 | 
        
           |  |  | 188 |                 'expectexception' => false,
 | 
        
           |  |  | 189 |                 'expected' => 2,
 | 
        
           |  |  | 190 |             ],
 | 
        
           |  |  | 191 |             'section 5 with skip validation' => [
 | 
        
           |  |  | 192 |                 'sectionnum' => 5,
 | 
        
           |  |  | 193 |                 'skip' => true,
 | 
        
           |  |  | 194 |                 'expectexception' => false,
 | 
        
           |  |  | 195 |                 'expected' => 5,
 | 
        
           |  |  | 196 |             ],
 | 
        
           |  |  | 197 |         ];
 | 
        
           |  |  | 198 |     }
 | 
        
           |  |  | 199 |   | 
        
           |  |  | 200 |     /**
 | 
        
           |  |  | 201 |      * Test create sections when there are sections with comonent (delegated sections) in the course.
 | 
        
           |  |  | 202 |      * @covers ::create
 | 
        
           |  |  | 203 |      * @covers ::create_delegated
 | 
        
           |  |  | 204 |      */
 | 
        
           |  |  | 205 |     public function test_create_with_delegated_sections(): void {
 | 
        
           |  |  | 206 |         global $DB;
 | 
        
           |  |  | 207 |         $this->resetAfterTest();
 | 
        
           |  |  | 208 |   | 
        
           |  |  | 209 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 210 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 211 |             ['createsections' => true],
 | 
        
           |  |  | 212 |         );
 | 
        
           |  |  | 213 |   | 
        
           |  |  | 214 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 215 |         $section = $sectionactions->create_delegated('mod_forum', 1);
 | 
        
           |  |  | 216 |         $this->assertEquals(2, $section->section);
 | 
        
           |  |  | 217 |         $delegateid = $section->id;
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 |         // Regular sections are created before delegated ones.
 | 
        
           |  |  | 220 |         $section = $sectionactions->create(2);
 | 
        
           |  |  | 221 |         $this->assertEquals(2, $section->section);
 | 
        
           |  |  | 222 |         $regularid = $section->id;
 | 
        
           |  |  | 223 |   | 
        
           |  |  | 224 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |         $section2 = $modinfo->get_section_info(2);
 | 
        
           |  |  | 227 |         $this->assertEquals($regularid, $section2->id);
 | 
        
           |  |  | 228 |         $this->assertEquals(2, $section2->section);
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 |         $sectiondelegated = $modinfo->get_section_info_by_component('mod_forum', 1);
 | 
        
           |  |  | 231 |         $this->assertEquals($delegateid, $sectiondelegated->id);
 | 
        
           |  |  | 232 |         $this->assertEquals(3, $sectiondelegated->section);
 | 
        
           |  |  | 233 |   | 
        
           |  |  | 234 |         // New delegates should be after the current delegate sections.
 | 
        
           |  |  | 235 |         $section = $sectionactions->create_delegated('mod_forum', 2);
 | 
        
           |  |  | 236 |         $this->assertEquals(4, $section->section);
 | 
        
           |  |  | 237 |     }
 | 
        
           |  |  | 238 |   | 
        
           |  |  | 239 |     /**
 | 
        
           |  |  | 240 |      * Test for create_if_missing method.
 | 
        
           |  |  | 241 |      * @covers ::create_if_missing
 | 
        
           |  |  | 242 |      * @dataProvider create_if_missing_provider
 | 
        
           |  |  | 243 |      * @param array $sectionnums the section numbers to create
 | 
        
           |  |  | 244 |      * @param bool $expected the expected result
 | 
        
           |  |  | 245 |      */
 | 
        
           |  |  | 246 |     public function test_create_if_missing(array $sectionnums, bool $expected): void {
 | 
        
           |  |  | 247 |         global $DB;
 | 
        
           |  |  | 248 |         $this->resetAfterTest();
 | 
        
           |  |  | 249 |   | 
        
           |  |  | 250 |         $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 2]);
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 253 |         $result = $sectionactions->create_if_missing($sectionnums);
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 |         $this->assertEquals($expected, $result);
 | 
        
           |  |  | 256 |   | 
        
           |  |  | 257 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 258 |         foreach ($sectionnums as $sectionnum) {
 | 
        
           |  |  | 259 |             $section = $modinfo->get_section_info($sectionnum);
 | 
        
           |  |  | 260 |             $this->assertEquals($sectionnum, $section->section);
 | 
        
           |  |  | 261 |         }
 | 
        
           |  |  | 262 |     }
 | 
        
           |  |  | 263 |   | 
        
           |  |  | 264 |     /**
 | 
        
           |  |  | 265 |      * Data provider for test_create_delegated.
 | 
        
           |  |  | 266 |      * @return array
 | 
        
           |  |  | 267 |      */
 | 
        
           |  |  | 268 |     public static function create_if_missing_provider(): array {
 | 
        
           |  |  | 269 |         return [
 | 
        
           |  |  | 270 |             'existing section' => [
 | 
        
           | 1441 | ariadna | 271 |                 'sectionnums' => [1],
 | 
        
           | 1 | efrain | 272 |                 'expected' => false,
 | 
        
           |  |  | 273 |             ],
 | 
        
           |  |  | 274 |             'unexisting section' => [
 | 
        
           | 1441 | ariadna | 275 |                 'sectionnums' => [3],
 | 
        
           | 1 | efrain | 276 |                 'expected' => true,
 | 
        
           |  |  | 277 |             ],
 | 
        
           |  |  | 278 |             'several existing sections' => [
 | 
        
           | 1441 | ariadna | 279 |                 'sectionnums' => [1, 2],
 | 
        
           | 1 | efrain | 280 |                 'expected' => false,
 | 
        
           |  |  | 281 |             ],
 | 
        
           |  |  | 282 |             'several unexisting sections' => [
 | 
        
           | 1441 | ariadna | 283 |                 'sectionnums' => [3, 4],
 | 
        
           | 1 | efrain | 284 |                 'expected' => true,
 | 
        
           |  |  | 285 |             ],
 | 
        
           |  |  | 286 |             'empty array' => [
 | 
        
           | 1441 | ariadna | 287 |                 'sectionnums' => [],
 | 
        
           | 1 | efrain | 288 |                 'expected' => false,
 | 
        
           |  |  | 289 |             ],
 | 
        
           |  |  | 290 |             'existent and unexistent sections' => [
 | 
        
           | 1441 | ariadna | 291 |                 'sectionnums' => [1, 2, 3, 4],
 | 
        
           | 1 | efrain | 292 |                 'expected' => true,
 | 
        
           |  |  | 293 |             ],
 | 
        
           |  |  | 294 |         ];
 | 
        
           |  |  | 295 |     }
 | 
        
           |  |  | 296 |   | 
        
           |  |  | 297 |     /**
 | 
        
           |  |  | 298 |      * Test create if missing when the course has delegated sections.
 | 
        
           |  |  | 299 |      * @covers ::create_if_missing
 | 
        
           |  |  | 300 |      * @covers ::create_delegated
 | 
        
           |  |  | 301 |      */
 | 
        
           |  |  | 302 |     public function test_create_if_missing_with_delegated_sections(): void {
 | 
        
           |  |  | 303 |         global $DB;
 | 
        
           |  |  | 304 |         $this->resetAfterTest();
 | 
        
           |  |  | 305 |   | 
        
           |  |  | 306 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 307 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 308 |             ['createsections' => true],
 | 
        
           |  |  | 309 |         );
 | 
        
           |  |  | 310 |   | 
        
           |  |  | 311 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 312 |         $section = $sectionactions->create_delegated('mod_forum', 1);
 | 
        
           |  |  | 313 |         $delegateid = $section->id;
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 |         $result = $sectionactions->create_if_missing([1, 2]);
 | 
        
           |  |  | 316 |         $this->assertTrue($result);
 | 
        
           |  |  | 317 |   | 
        
           |  |  | 318 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 319 |         $section = $modinfo->get_section_info(2);
 | 
        
           |  |  | 320 |         $this->assertEquals(2, $section->section);
 | 
        
           |  |  | 321 |         $this->assertNotEquals($delegateid, $section->id);
 | 
        
           |  |  | 322 |         $delegatedsection = $modinfo->get_section_info_by_id($delegateid);
 | 
        
           |  |  | 323 |         $this->assertEquals(3, $delegatedsection->section);
 | 
        
           |  |  | 324 |   | 
        
           |  |  | 325 |         $result = $sectionactions->create_if_missing([1, 2]);
 | 
        
           |  |  | 326 |         $this->assertFalse($result);
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 |         $result = $sectionactions->create_if_missing([1, 2, 3]);
 | 
        
           |  |  | 329 |         $this->assertTrue($result);
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 332 |         $section = $modinfo->get_section_info(3);
 | 
        
           |  |  | 333 |         $this->assertEquals(3, $section->section);
 | 
        
           |  |  | 334 |         $this->assertNotEquals($delegateid, $section->id);
 | 
        
           |  |  | 335 |         $delegatedsection = $modinfo->get_section_info_by_id($delegateid);
 | 
        
           |  |  | 336 |         $this->assertEquals(4, $delegatedsection->section);
 | 
        
           |  |  | 337 |   | 
        
           |  |  | 338 |         $result = $sectionactions->create_if_missing([1, 2, 3]);
 | 
        
           |  |  | 339 |         $this->assertFalse($result);
 | 
        
           |  |  | 340 |     }
 | 
        
           |  |  | 341 |   | 
        
           |  |  | 342 |     /**
 | 
        
           |  |  | 343 |      * Test for delete method.
 | 
        
           |  |  | 344 |      * @covers ::delete
 | 
        
           |  |  | 345 |      */
 | 
        
           |  |  | 346 |     public function test_delete(): void {
 | 
        
           |  |  | 347 |         global $DB;
 | 
        
           |  |  | 348 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 349 |   | 
        
           |  |  | 350 |         $generator = $this->getDataGenerator();
 | 
        
           |  |  | 351 |   | 
        
           |  |  | 352 |         $course = $generator->create_course(
 | 
        
           |  |  | 353 |             ['numsections' => 6, 'format' => 'topics'],
 | 
        
           |  |  | 354 |             ['createsections' => true]
 | 
        
           |  |  | 355 |         );
 | 
        
           |  |  | 356 |         $assign0 = $generator->create_module('assign', ['course' => $course, 'section' => 0]);
 | 
        
           |  |  | 357 |         $assign1 = $generator->create_module('assign', ['course' => $course, 'section' => 1]);
 | 
        
           |  |  | 358 |         $assign21 = $generator->create_module('assign', ['course' => $course, 'section' => 2]);
 | 
        
           |  |  | 359 |         $assign22 = $generator->create_module('assign', ['course' => $course, 'section' => 2]);
 | 
        
           |  |  | 360 |         $assign3 = $generator->create_module('assign', ['course' => $course, 'section' => 3]);
 | 
        
           |  |  | 361 |         $assign5 = $generator->create_module('assign', ['course' => $course, 'section' => 5]);
 | 
        
           |  |  | 362 |         $assign6 = $generator->create_module('assign', ['course' => $course, 'section' => 6]);
 | 
        
           |  |  | 363 |   | 
        
           |  |  | 364 |         $this->setAdminUser();
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 367 |         $sections = get_fast_modinfo($course)->get_section_info_all();
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |         // Attempt to delete 0-section.
 | 
        
           |  |  | 370 |         $this->assertFalse($sectionactions->delete($sections[0], true));
 | 
        
           |  |  | 371 |         $this->assertTrue($DB->record_exists('course_modules', ['id' => $assign0->cmid]));
 | 
        
           |  |  | 372 |         $this->assertEquals(6, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 373 |   | 
        
           |  |  | 374 |         // Delete last section.
 | 
        
           |  |  | 375 |         $this->assertTrue($sectionactions->delete($sections[6], true));
 | 
        
           |  |  | 376 |         $this->assertFalse($DB->record_exists('course_modules', ['id' => $assign6->cmid]));
 | 
        
           |  |  | 377 |         $this->assertEquals(5, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 378 |   | 
        
           |  |  | 379 |         // Delete empty section.
 | 
        
           |  |  | 380 |         $this->assertTrue($sectionactions->delete($sections[4], false));
 | 
        
           |  |  | 381 |         $this->assertEquals(4, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 382 |   | 
        
           |  |  | 383 |         // Delete section in the middle (2).
 | 
        
           |  |  | 384 |         $this->assertFalse($sectionactions->delete($sections[2], false));
 | 
        
           |  |  | 385 |         $this->assertEquals(4, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 386 |         $sections = get_fast_modinfo($course)->get_section_info_all();
 | 
        
           |  |  | 387 |         $this->assertTrue($sectionactions->delete($sections[2], true));
 | 
        
           |  |  | 388 |         $this->assertFalse($DB->record_exists('course_modules', ['id' => $assign21->cmid]));
 | 
        
           |  |  | 389 |         $this->assertFalse($DB->record_exists('course_modules', ['id' => $assign22->cmid]));
 | 
        
           |  |  | 390 |         $this->assertEquals(3, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 391 |         $this->assertEquals(
 | 
        
           |  |  | 392 |             [
 | 
        
           |  |  | 393 |   | 
        
           |  |  | 394 |                 1 => [$assign1->cmid],
 | 
        
           |  |  | 395 |                 2 => [$assign3->cmid],
 | 
        
           |  |  | 396 |                 3 => [$assign5->cmid],
 | 
        
           |  |  | 397 |             ],
 | 
        
           |  |  | 398 |             get_fast_modinfo($course)->sections
 | 
        
           |  |  | 399 |         );
 | 
        
           |  |  | 400 |   | 
        
           |  |  | 401 |         // Remove marked section.
 | 
        
           |  |  | 402 |         course_set_marker($course->id, 1);
 | 
        
           |  |  | 403 |         $this->assertTrue(course_get_format($course)->is_section_current(1));
 | 
        
           |  |  | 404 |         $this->assertTrue($sectionactions->delete(
 | 
        
           |  |  | 405 |             get_fast_modinfo($course)->get_section_info(1),
 | 
        
           |  |  | 406 |             true
 | 
        
           |  |  | 407 |         ));
 | 
        
           |  |  | 408 |         $this->assertFalse(course_get_format($course)->is_section_current(1));
 | 
        
           |  |  | 409 |     }
 | 
        
           |  |  | 410 |   | 
        
           |  |  | 411 |     /**
 | 
        
           |  |  | 412 |      * Test that triggering a course_section_deleted event works as expected.
 | 
        
           |  |  | 413 |      * @covers ::delete
 | 
        
           |  |  | 414 |      */
 | 
        
           |  |  | 415 |     public function test_section_deleted_event(): void {
 | 
        
           |  |  | 416 |         global $USER, $DB;
 | 
        
           |  |  | 417 |         $this->resetAfterTest();
 | 
        
           |  |  | 418 |         $sink = $this->redirectEvents();
 | 
        
           |  |  | 419 |   | 
        
           |  |  | 420 |         // Create the course with sections.
 | 
        
           |  |  | 421 |         $course = $this->getDataGenerator()->create_course(['numsections' => 10], ['createsections' => true]);
 | 
        
           |  |  | 422 |         $coursecontext = \context_course::instance($course->id);
 | 
        
           |  |  | 423 |   | 
        
           |  |  | 424 |         $section = get_fast_modinfo($course)->get_section_info(10);
 | 
        
           |  |  | 425 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 426 |   | 
        
           |  |  | 427 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 428 |         $sectionactions->delete($section);
 | 
        
           |  |  | 429 |   | 
        
           |  |  | 430 |         $events = $sink->get_events();
 | 
        
           |  |  | 431 |         $event = array_pop($events); // Delete section event.
 | 
        
           |  |  | 432 |         $sink->close();
 | 
        
           |  |  | 433 |   | 
        
           |  |  | 434 |         // Validate event data.
 | 
        
           |  |  | 435 |         $this->assertInstanceOf('\core\event\course_section_deleted', $event);
 | 
        
           |  |  | 436 |         $this->assertEquals('course_sections', $event->objecttable);
 | 
        
           |  |  | 437 |         $this->assertEquals($section->id, $event->objectid);
 | 
        
           |  |  | 438 |         $this->assertEquals($course->id, $event->courseid);
 | 
        
           |  |  | 439 |         $this->assertEquals($coursecontext->id, $event->contextid);
 | 
        
           |  |  | 440 |         $this->assertEquals($section->section, $event->other['sectionnum']);
 | 
        
           |  |  | 441 |         $expecteddesc = "The user with id '{$event->userid}' deleted section number '{$event->other['sectionnum']}' " .
 | 
        
           |  |  | 442 |             "(section name '{$event->other['sectionname']}') for the course with id '{$event->courseid}'";
 | 
        
           |  |  | 443 |         $this->assertEquals($expecteddesc, $event->get_description());
 | 
        
           |  |  | 444 |         $this->assertEquals($sectionrecord, $event->get_record_snapshot('course_sections', $event->objectid));
 | 
        
           |  |  | 445 |         $this->assertNull($event->get_url());
 | 
        
           |  |  | 446 |         $this->assertEventContextNotUsed($event);
 | 
        
           |  |  | 447 |     }
 | 
        
           |  |  | 448 |   | 
        
           |  |  | 449 |     /**
 | 
        
           |  |  | 450 |      * Test async section deletion hook.
 | 
        
           |  |  | 451 |      * @covers ::delete
 | 
        
           |  |  | 452 |      */
 | 
        
           |  |  | 453 |     public function test_async_section_deletion_hook_implemented(): void {
 | 
        
           |  |  | 454 |         // Async section deletion (provided section contains modules), depends on the 'true' being returned by at least one plugin
 | 
        
           |  |  | 455 |         // implementing the 'course_module_adhoc_deletion_recommended' hook. In core, is implemented by the course recyclebin,
 | 
        
           |  |  | 456 |         // which will only return true if the plugin is enabled. To make sure async deletion occurs, this test enables recyclebin.
 | 
        
           |  |  | 457 |         global $DB, $USER;
 | 
        
           |  |  | 458 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 459 |         $this->setAdminUser();
 | 
        
           |  |  | 460 |   | 
        
           |  |  | 461 |         // Ensure recyclebin is enabled.
 | 
        
           |  |  | 462 |         set_config('coursebinenable', true, 'tool_recyclebin');
 | 
        
           |  |  | 463 |   | 
        
           |  |  | 464 |         // Create course, module and context.
 | 
        
           |  |  | 465 |         $generator = $this->getDataGenerator();
 | 
        
           |  |  | 466 |         $course = $generator->create_course(['numsections' => 4, 'format' => 'topics'], ['createsections' => true]);
 | 
        
           |  |  | 467 |         $assign0 = $generator->create_module('assign', ['course' => $course, 'section' => 2]);
 | 
        
           |  |  | 468 |         $assign1 = $generator->create_module('assign', ['course' => $course, 'section' => 2]);
 | 
        
           |  |  | 469 |         $assign2 = $generator->create_module('assign', ['course' => $course, 'section' => 2]);
 | 
        
           |  |  | 470 |         $assign3 = $generator->create_module('assign', ['course' => $course, 'section' => 0]);
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 473 |   | 
        
           |  |  | 474 |         // Delete empty section. No difference from normal, synchronous behaviour.
 | 
        
           |  |  | 475 |         $this->assertTrue($sectionactions->delete(get_fast_modinfo($course)->get_section_info(4), false, true));
 | 
        
           |  |  | 476 |         $this->assertEquals(3, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 477 |   | 
        
           |  |  | 478 |         // Delete a module in section 2 (using async). Need to verify this doesn't generate two tasks when we delete
 | 
        
           |  |  | 479 |         // the section in the next step.
 | 
        
           |  |  | 480 |         course_delete_module($assign2->cmid, true);
 | 
        
           |  |  | 481 |   | 
        
           |  |  | 482 |         // Confirm that the module is pending deletion in its current section.
 | 
        
           |  |  | 483 |         $section = $DB->get_record('course_sections', ['course' => $course->id, 'section' => '2']); // For event comparison.
 | 
        
           |  |  | 484 |         $this->assertEquals(true, $DB->record_exists('course_modules', ['id' => $assign2->cmid, 'deletioninprogress' => 1,
 | 
        
           |  |  | 485 |             'section' => $section->id]));
 | 
        
           |  |  | 486 |   | 
        
           |  |  | 487 |         // Non-empty section, no forcedelete, so no change.
 | 
        
           |  |  | 488 |         $this->assertFalse($sectionactions->delete(get_fast_modinfo($course)->get_section_info(2), false, true));
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 |         $sink = $this->redirectEvents();
 | 
        
           |  |  | 491 |         $this->assertTrue($sectionactions->delete(get_fast_modinfo($course)->get_section_info(2), true, true));
 | 
        
           |  |  | 492 |   | 
        
           |  |  | 493 |         // Now, confirm that:
 | 
        
           |  |  | 494 |         // a) the section's modules have been flagged for deletion and moved to section 0 and;
 | 
        
           |  |  | 495 |         // b) the section has been deleted and;
 | 
        
           |  |  | 496 |         // c) course_section_deleted event has been fired. The course_module_deleted events will only fire once they have been
 | 
        
           |  |  | 497 |         // removed from section 0 via the adhoc task.
 | 
        
           |  |  | 498 |   | 
        
           |  |  | 499 |         // Modules should have been flagged for deletion and moved to section 0.
 | 
        
           |  |  | 500 |         $sectionid = $DB->get_field('course_sections', 'id', ['course' => $course->id, 'section' => 0]);
 | 
        
           |  |  | 501 |         $this->assertEquals(
 | 
        
           |  |  | 502 |             3,
 | 
        
           |  |  | 503 |             $DB->count_records('course_modules', ['section' => $sectionid, 'deletioninprogress' => 1])
 | 
        
           |  |  | 504 |         );
 | 
        
           |  |  | 505 |   | 
        
           |  |  | 506 |         // Confirm the section has been deleted.
 | 
        
           |  |  | 507 |         $this->assertEquals(2, course_get_format($course)->get_last_section_number());
 | 
        
           |  |  | 508 |   | 
        
           |  |  | 509 |         // Check event fired.
 | 
        
           |  |  | 510 |         $events = $sink->get_events();
 | 
        
           |  |  | 511 |         $event = array_pop($events);
 | 
        
           |  |  | 512 |         $sink->close();
 | 
        
           |  |  | 513 |         $this->assertInstanceOf('\core\event\course_section_deleted', $event);
 | 
        
           |  |  | 514 |         $this->assertEquals($section->id, $event->objectid);
 | 
        
           |  |  | 515 |         $this->assertEquals($USER->id, $event->userid);
 | 
        
           |  |  | 516 |         $this->assertEquals('course_sections', $event->objecttable);
 | 
        
           |  |  | 517 |         $this->assertEquals(null, $event->get_url());
 | 
        
           |  |  | 518 |         $this->assertEquals($section, $event->get_record_snapshot('course_sections', $section->id));
 | 
        
           |  |  | 519 |   | 
        
           |  |  | 520 |         // Now, run the adhoc task to delete the modules from section 0.
 | 
        
           |  |  | 521 |         $sink = $this->redirectEvents(); // To capture the events.
 | 
        
           |  |  | 522 |         \phpunit_util::run_all_adhoc_tasks();
 | 
        
           |  |  | 523 |   | 
        
           |  |  | 524 |         // Confirm the modules have been deleted.
 | 
        
           |  |  | 525 |         list($insql, $assignids) = $DB->get_in_or_equal([$assign0->cmid, $assign1->cmid, $assign2->cmid]);
 | 
        
           |  |  | 526 |         $cmcount = $DB->count_records_select('course_modules', 'id ' . $insql, $assignids);
 | 
        
           |  |  | 527 |         $this->assertEmpty($cmcount);
 | 
        
           |  |  | 528 |   | 
        
           |  |  | 529 |         // Confirm other modules in section 0 still remain.
 | 
        
           |  |  | 530 |         $this->assertEquals(1, $DB->count_records('course_modules', ['id' => $assign3->cmid]));
 | 
        
           |  |  | 531 |   | 
        
           |  |  | 532 |         // Confirm that events were generated for all 3 of the modules.
 | 
        
           |  |  | 533 |         $events = $sink->get_events();
 | 
        
           |  |  | 534 |         $sink->close();
 | 
        
           |  |  | 535 |         $count = 0;
 | 
        
           |  |  | 536 |         while (!empty($events)) {
 | 
        
           |  |  | 537 |             $event = array_pop($events);
 | 
        
           |  |  | 538 |             if ($event instanceof \core\event\course_module_deleted &&
 | 
        
           |  |  | 539 |                 in_array($event->objectid, [$assign0->cmid, $assign1->cmid, $assign2->cmid])) {
 | 
        
           |  |  | 540 |                 $count++;
 | 
        
           |  |  | 541 |             }
 | 
        
           |  |  | 542 |         }
 | 
        
           |  |  | 543 |         $this->assertEquals(3, $count);
 | 
        
           |  |  | 544 |     }
 | 
        
           |  |  | 545 |   | 
        
           |  |  | 546 |     /**
 | 
        
           |  |  | 547 |      * Test section update method.
 | 
        
           |  |  | 548 |      *
 | 
        
           |  |  | 549 |      * @covers ::update
 | 
        
           |  |  | 550 |      * @dataProvider update_provider
 | 
        
           |  |  | 551 |      * @param string $fieldname the name of the field to update
 | 
        
           |  |  | 552 |      * @param int|string $value the value to set
 | 
        
           |  |  | 553 |      * @param int|string $expected the expected value after the update ('=' to specify the same value as original field)
 | 
        
           |  |  | 554 |      * @param bool $expectexception if the method should throw an exception
 | 
        
           |  |  | 555 |      */
 | 
        
           |  |  | 556 |     public function test_update(
 | 
        
           |  |  | 557 |         string $fieldname,
 | 
        
           |  |  | 558 |         int|string $value,
 | 
        
           |  |  | 559 |         int|string $expected,
 | 
        
           |  |  | 560 |         bool $expectexception
 | 
        
           |  |  | 561 |     ): void {
 | 
        
           |  |  | 562 |         global $DB;
 | 
        
           |  |  | 563 |         $this->resetAfterTest();
 | 
        
           |  |  | 564 |   | 
        
           |  |  | 565 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 566 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 567 |             ['createsections' => true]
 | 
        
           |  |  | 568 |         );
 | 
        
           |  |  | 569 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 570 |   | 
        
           |  |  | 571 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 572 |         $this->assertNotEquals($value, $sectionrecord->$fieldname);
 | 
        
           |  |  | 573 |         $this->assertNotEquals($value, $section->$fieldname);
 | 
        
           |  |  | 574 |   | 
        
           |  |  | 575 |         if ($expectexception) {
 | 
        
           |  |  | 576 |             $this->expectException(\moodle_exception::class);
 | 
        
           |  |  | 577 |         }
 | 
        
           |  |  | 578 |   | 
        
           |  |  | 579 |         if ($expected === '=') {
 | 
        
           |  |  | 580 |             $expected = $section->$fieldname;
 | 
        
           |  |  | 581 |         }
 | 
        
           |  |  | 582 |   | 
        
           |  |  | 583 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 584 |         $sectionactions->update($section, [$fieldname => $value]);
 | 
        
           |  |  | 585 |   | 
        
           |  |  | 586 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 587 |         $this->assertEquals($expected, $sectionrecord->$fieldname);
 | 
        
           |  |  | 588 |   | 
        
           |  |  | 589 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 590 |         $this->assertEquals($expected, $section->$fieldname);
 | 
        
           |  |  | 591 |     }
 | 
        
           |  |  | 592 |   | 
        
           |  |  | 593 |     /**
 | 
        
           |  |  | 594 |      * Data provider for test_update.
 | 
        
           |  |  | 595 |      * @return array
 | 
        
           |  |  | 596 |      */
 | 
        
           |  |  | 597 |     public static function update_provider(): array {
 | 
        
           |  |  | 598 |         return [
 | 
        
           |  |  | 599 |             'Id will not be updated' => [
 | 
        
           |  |  | 600 |                 'fieldname' => 'id',
 | 
        
           |  |  | 601 |                 'value' => -1,
 | 
        
           |  |  | 602 |                 'expected' => '=',
 | 
        
           |  |  | 603 |                 'expectexception' => false,
 | 
        
           |  |  | 604 |             ],
 | 
        
           |  |  | 605 |             'Course will not be updated' => [
 | 
        
           |  |  | 606 |                 'fieldname' => 'course',
 | 
        
           |  |  | 607 |                 'value' => -1,
 | 
        
           |  |  | 608 |                 'expected' => '=',
 | 
        
           |  |  | 609 |                 'expectexception' => false,
 | 
        
           |  |  | 610 |             ],
 | 
        
           |  |  | 611 |             'Section number will not be updated' => [
 | 
        
           |  |  | 612 |                 'fieldname' => 'section',
 | 
        
           |  |  | 613 |                 'value' => -1,
 | 
        
           |  |  | 614 |                 'expected' => '=',
 | 
        
           |  |  | 615 |                 'expectexception' => false,
 | 
        
           |  |  | 616 |             ],
 | 
        
           |  |  | 617 |             'Sequence will be updated' => [
 | 
        
           |  |  | 618 |                 'fieldname' => 'name',
 | 
        
           |  |  | 619 |                 'value' => 'new name',
 | 
        
           |  |  | 620 |                 'expected' => 'new name',
 | 
        
           |  |  | 621 |                 'expectexception' => false,
 | 
        
           |  |  | 622 |             ],
 | 
        
           |  |  | 623 |             'Summary can be updated' => [
 | 
        
           |  |  | 624 |                 'fieldname' => 'summary',
 | 
        
           |  |  | 625 |                 'value' => 'new summary',
 | 
        
           |  |  | 626 |                 'expected' => 'new summary',
 | 
        
           |  |  | 627 |                 'expectexception' => false,
 | 
        
           |  |  | 628 |             ],
 | 
        
           |  |  | 629 |             'Visible can be updated' => [
 | 
        
           |  |  | 630 |                 'fieldname' => 'visible',
 | 
        
           |  |  | 631 |                 'value' => 0,
 | 
        
           |  |  | 632 |                 'expected' => 0,
 | 
        
           |  |  | 633 |                 'expectexception' => false,
 | 
        
           |  |  | 634 |             ],
 | 
        
           |  |  | 635 |             'component can be updated' => [
 | 
        
           |  |  | 636 |                 'fieldname' => 'component',
 | 
        
           |  |  | 637 |                 'value' => 'mod_assign',
 | 
        
           |  |  | 638 |                 'expected' => 'mod_assign',
 | 
        
           |  |  | 639 |                 'expectexception' => false,
 | 
        
           |  |  | 640 |             ],
 | 
        
           |  |  | 641 |             'itemid can be updated' => [
 | 
        
           |  |  | 642 |                 'fieldname' => 'itemid',
 | 
        
           |  |  | 643 |                 'value' => 1,
 | 
        
           |  |  | 644 |                 'expected' => 1,
 | 
        
           |  |  | 645 |                 'expectexception' => false,
 | 
        
           |  |  | 646 |             ],
 | 
        
           |  |  | 647 |             'Long names throws and exception' => [
 | 
        
           |  |  | 648 |                 'fieldname' => 'name',
 | 
        
           |  |  | 649 |                 'value' => str_repeat('a', 256),
 | 
        
           |  |  | 650 |                 'expected' => '=',
 | 
        
           |  |  | 651 |                 'expectexception' => true,
 | 
        
           |  |  | 652 |             ],
 | 
        
           |  |  | 653 |         ];
 | 
        
           |  |  | 654 |     }
 | 
        
           |  |  | 655 |   | 
        
           |  |  | 656 |     /**
 | 
        
           |  |  | 657 |      * Test section update method updating several values at once.
 | 
        
           |  |  | 658 |      *
 | 
        
           |  |  | 659 |      * @covers ::update
 | 
        
           |  |  | 660 |      */
 | 
        
           |  |  | 661 |     public function test_update_multiple_fields(): void {
 | 
        
           |  |  | 662 |         global $DB;
 | 
        
           |  |  | 663 |         $this->resetAfterTest();
 | 
        
           |  |  | 664 |   | 
        
           |  |  | 665 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 666 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 667 |             ['createsections' => true]
 | 
        
           |  |  | 668 |         );
 | 
        
           |  |  | 669 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 670 |   | 
        
           |  |  | 671 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 672 |         $this->assertEquals(1, $sectionrecord->visible);
 | 
        
           |  |  | 673 |         $this->assertNull($section->name);
 | 
        
           |  |  | 674 |   | 
        
           |  |  | 675 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 676 |         $sectionactions->update($section, ['name' => 'New name', 'visible' => 0]);
 | 
        
           |  |  | 677 |   | 
        
           |  |  | 678 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 679 |         $this->assertEquals('New name', $sectionrecord->name);
 | 
        
           |  |  | 680 |         $this->assertEquals(0, $sectionrecord->visible);
 | 
        
           |  |  | 681 |   | 
        
           |  |  | 682 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 683 |         $this->assertEquals('New name', $section->name);
 | 
        
           |  |  | 684 |         $this->assertEquals(0, $section->visible);
 | 
        
           |  |  | 685 |     }
 | 
        
           |  |  | 686 |   | 
        
           |  |  | 687 |     /**
 | 
        
           |  |  | 688 |      * Test updating a section trigger a course section update log event.
 | 
        
           |  |  | 689 |      *
 | 
        
           |  |  | 690 |      * @covers ::update
 | 
        
           |  |  | 691 |      */
 | 
        
           |  |  | 692 |     public function test_course_section_updated_event(): void {
 | 
        
           |  |  | 693 |         $this->resetAfterTest();
 | 
        
           |  |  | 694 |   | 
        
           |  |  | 695 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 696 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 697 |             ['createsections' => true]
 | 
        
           |  |  | 698 |         );
 | 
        
           |  |  | 699 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 700 |   | 
        
           |  |  | 701 |         $sink = $this->redirectEvents();
 | 
        
           |  |  | 702 |   | 
        
           |  |  | 703 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 704 |         $sectionactions->update($section, ['name' => 'New name', 'visible' => 0]);
 | 
        
           |  |  | 705 |   | 
        
           |  |  | 706 |         $events = $sink->get_events();
 | 
        
           |  |  | 707 |         $event = reset($events);
 | 
        
           |  |  | 708 |   | 
        
           |  |  | 709 |         // Check that the event data is valid.
 | 
        
           |  |  | 710 |         $this->assertInstanceOf('\core\event\course_section_updated', $event);
 | 
        
           |  |  | 711 |         $data = $event->get_data();
 | 
        
           |  |  | 712 |         $this->assertEquals(\context_course::instance($course->id), $event->get_context());
 | 
        
           |  |  | 713 |         $this->assertEquals($section->id, $data['objectid']);
 | 
        
           |  |  | 714 |     }
 | 
        
           |  |  | 715 |   | 
        
           |  |  | 716 |     /**
 | 
        
           |  |  | 717 |      * Test section update change the modified date.
 | 
        
           |  |  | 718 |      *
 | 
        
           |  |  | 719 |      * @covers ::update
 | 
        
           |  |  | 720 |      */
 | 
        
           |  |  | 721 |     public function test_update_time_modified(): void {
 | 
        
           |  |  | 722 |         global $DB;
 | 
        
           |  |  | 723 |         $this->resetAfterTest();
 | 
        
           |  |  | 724 |   | 
        
           |  |  | 725 |         // Create the course with sections.
 | 
        
           |  |  | 726 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 727 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 728 |             ['createsections' => true]
 | 
        
           |  |  | 729 |         );
 | 
        
           |  |  | 730 |         $section = get_fast_modinfo($course)->get_section_info(1);
 | 
        
           |  |  | 731 |   | 
        
           |  |  | 732 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 733 |         $oldtimemodified = $sectionrecord->timemodified;
 | 
        
           |  |  | 734 |   | 
        
           |  |  | 735 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 736 |   | 
        
           |  |  | 737 |         // Ensuring that the section update occurs at a different timestamp.
 | 
        
           |  |  | 738 |         $this->waitForSecond();
 | 
        
           |  |  | 739 |   | 
        
           |  |  | 740 |         // The timemodified should only be updated if the section is actually updated.
 | 
        
           |  |  | 741 |         $result = $sectionactions->update($section, []);
 | 
        
           |  |  | 742 |         $this->assertFalse($result);
 | 
        
           |  |  | 743 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 744 |         $this->assertEquals($oldtimemodified, $sectionrecord->timemodified);
 | 
        
           |  |  | 745 |   | 
        
           |  |  | 746 |         // Now update something to prove timemodified changes.
 | 
        
           |  |  | 747 |         $result = $sectionactions->update($section, ['name' => 'New name']);
 | 
        
           |  |  | 748 |         $this->assertTrue($result);
 | 
        
           |  |  | 749 |         $sectionrecord = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 750 |         $this->assertGreaterThan($oldtimemodified, $sectionrecord->timemodified);
 | 
        
           |  |  | 751 |     }
 | 
        
           |  |  | 752 |   | 
        
           |  |  | 753 |     /**
 | 
        
           |  |  | 754 |      * Test section updating visibility will hide or show section activities.
 | 
        
           |  |  | 755 |      *
 | 
        
           |  |  | 756 |      * @covers ::update
 | 
        
           |  |  | 757 |      */
 | 
        
           |  |  | 758 |     public function test_update_hide_section_activities(): void {
 | 
        
           |  |  | 759 |         global $DB;
 | 
        
           |  |  | 760 |         $this->resetAfterTest();
 | 
        
           |  |  | 761 |   | 
        
           |  |  | 762 |         // Create 4 activities (visible, visible, hidden, hidden).
 | 
        
           |  |  | 763 |         $course = $this->getDataGenerator()->create_course(
 | 
        
           |  |  | 764 |             ['format' => 'topics', 'numsections' => 1],
 | 
        
           |  |  | 765 |             ['createsections' => true]
 | 
        
           |  |  | 766 |         );
 | 
        
           |  |  | 767 |         $activity1 = $this->getDataGenerator()->create_module(
 | 
        
           |  |  | 768 |             'assign',
 | 
        
           |  |  | 769 |             ['course' => $course->id, 'section' => 1]
 | 
        
           |  |  | 770 |         );
 | 
        
           |  |  | 771 |         $activity2 = $this->getDataGenerator()->create_module(
 | 
        
           |  |  | 772 |             'assign',
 | 
        
           |  |  | 773 |             ['course' => $course->id, 'section' => 1]
 | 
        
           |  |  | 774 |         );
 | 
        
           |  |  | 775 |         $activity3 = $this->getDataGenerator()->create_module(
 | 
        
           |  |  | 776 |             'assign',
 | 
        
           |  |  | 777 |             ['course' => $course->id, 'section' => 1, 'visible' => 0]
 | 
        
           |  |  | 778 |         );
 | 
        
           |  |  | 779 |         $activity4 = $this->getDataGenerator()->create_module(
 | 
        
           |  |  | 780 |             'assign',
 | 
        
           |  |  | 781 |             ['course' => $course->id, 'section' => 1, 'visible' => 0]
 | 
        
           |  |  | 782 |         );
 | 
        
           |  |  | 783 |   | 
        
           |  |  | 784 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 785 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 786 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 787 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 788 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 789 |         $this->assertEquals(1, $cm1->visible);
 | 
        
           |  |  | 790 |         $this->assertEquals(1, $cm2->visible);
 | 
        
           |  |  | 791 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 792 |         $this->assertEquals(0, $cm4->visible);
 | 
        
           |  |  | 793 |   | 
        
           |  |  | 794 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 795 |   | 
        
           |  |  | 796 |         // Validate hidding section hides all activities.
 | 
        
           |  |  | 797 |         $section = $modinfo->get_section_info(1);
 | 
        
           |  |  | 798 |         $sectionactions->update($section, ['visible' => 0]);
 | 
        
           |  |  | 799 |   | 
        
           |  |  | 800 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 801 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 802 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 803 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 804 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 805 |         $this->assertEquals(0, $cm1->visible);
 | 
        
           |  |  | 806 |         $this->assertEquals(0, $cm2->visible);
 | 
        
           |  |  | 807 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 808 |         $this->assertEquals(0, $cm4->visible);
 | 
        
           |  |  | 809 |   | 
        
           |  |  | 810 |         // Validate showing the section restores the previous visibility.
 | 
        
           |  |  | 811 |         $section = $modinfo->get_section_info(1);
 | 
        
           |  |  | 812 |         $sectionactions->update($section, ['visible' => 1]);
 | 
        
           |  |  | 813 |   | 
        
           |  |  | 814 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 815 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 816 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 817 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 818 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 819 |         $this->assertEquals(1, $cm1->visible);
 | 
        
           |  |  | 820 |         $this->assertEquals(1, $cm2->visible);
 | 
        
           |  |  | 821 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 822 |         $this->assertEquals(0, $cm4->visible);
 | 
        
           |  |  | 823 |   | 
        
           |  |  | 824 |         // Swap two activities visibility to alter visible values.
 | 
        
           |  |  | 825 |         set_coursemodule_visible($cm2->id, 0, 0, true);
 | 
        
           |  |  | 826 |         set_coursemodule_visible($cm4->id, 1, 1, true);
 | 
        
           |  |  | 827 |   | 
        
           |  |  | 828 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 829 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 830 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 831 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 832 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 833 |         $this->assertEquals(1, $cm1->visible);
 | 
        
           |  |  | 834 |         $this->assertEquals(0, $cm2->visible);
 | 
        
           |  |  | 835 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 836 |         $this->assertEquals(1, $cm4->visible);
 | 
        
           |  |  | 837 |   | 
        
           |  |  | 838 |         // Validate hidding the section again.
 | 
        
           |  |  | 839 |         $section = $modinfo->get_section_info(1);
 | 
        
           |  |  | 840 |         $sectionactions->update($section, ['visible' => 0]);
 | 
        
           |  |  | 841 |   | 
        
           |  |  | 842 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 843 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 844 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 845 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 846 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 847 |         $this->assertEquals(0, $cm1->visible);
 | 
        
           |  |  | 848 |         $this->assertEquals(0, $cm2->visible);
 | 
        
           |  |  | 849 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 850 |         $this->assertEquals(0, $cm4->visible);
 | 
        
           |  |  | 851 |   | 
        
           |  |  | 852 |         // Validate showing the section once more to check previous state is restored.
 | 
        
           |  |  | 853 |         $section = $modinfo->get_section_info(1);
 | 
        
           |  |  | 854 |         $sectionactions->update($section, ['visible' => 1]);
 | 
        
           |  |  | 855 |   | 
        
           |  |  | 856 |         $modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 857 |         $cm1 = $modinfo->get_cm($activity1->cmid);
 | 
        
           |  |  | 858 |         $cm2 = $modinfo->get_cm($activity2->cmid);
 | 
        
           |  |  | 859 |         $cm3 = $modinfo->get_cm($activity3->cmid);
 | 
        
           |  |  | 860 |         $cm4 = $modinfo->get_cm($activity4->cmid);
 | 
        
           |  |  | 861 |         $this->assertEquals(1, $cm1->visible);
 | 
        
           |  |  | 862 |         $this->assertEquals(0, $cm2->visible);
 | 
        
           |  |  | 863 |         $this->assertEquals(0, $cm3->visible);
 | 
        
           |  |  | 864 |         $this->assertEquals(1, $cm4->visible);
 | 
        
           |  |  | 865 |     }
 | 
        
           |  |  | 866 |   | 
        
           |  |  | 867 |     /**
 | 
        
           |  |  | 868 |      * Test that the preprocess_section_name method can alter the section rename value.
 | 
        
           |  |  | 869 |      *
 | 
        
           |  |  | 870 |      * @covers ::update
 | 
        
           |  |  | 871 |      * @covers ::preprocess_delegated_section_fields
 | 
        
           |  |  | 872 |      */
 | 
        
           |  |  | 873 |     public function test_preprocess_section_name(): void {
 | 
        
           |  |  | 874 |         global $DB, $CFG;
 | 
        
           |  |  | 875 |         $this->resetAfterTest();
 | 
        
           |  |  | 876 |   | 
        
           |  |  | 877 |         require_once($CFG->libdir . '/tests/fixtures/sectiondelegatetest.php');
 | 
        
           |  |  | 878 |   | 
        
           |  |  | 879 |         $course = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 880 |   | 
        
           |  |  | 881 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 882 |         $section = $sectionactions->create_delegated('test_component', 1);
 | 
        
           |  |  | 883 |   | 
        
           |  |  | 884 |         $result = $sectionactions->update($section, ['name' => 'new_name']);
 | 
        
           |  |  | 885 |         $this->assertTrue($result);
 | 
        
           |  |  | 886 |   | 
        
           |  |  | 887 |         $section = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 888 |         $this->assertEquals('new_name_suffix', $section->name);
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |         $sectioninfo = get_fast_modinfo($course->id)->get_section_info_by_id($section->id);
 | 
        
           |  |  | 891 |         $this->assertEquals('new_name_suffix', $sectioninfo->name);
 | 
        
           |  |  | 892 |   | 
        
           |  |  | 893 |         // Validate null name.
 | 
        
           |  |  | 894 |         $section = $sectionactions->create_delegated('test_component', 1, (object)['name' => 'sample']);
 | 
        
           |  |  | 895 |   | 
        
           |  |  | 896 |         $result = $sectionactions->update($section, ['name' => null]);
 | 
        
           |  |  | 897 |         $this->assertTrue($result);
 | 
        
           |  |  | 898 |   | 
        
           |  |  | 899 |         $section = $DB->get_record('course_sections', ['id' => $section->id]);
 | 
        
           |  |  | 900 |         $this->assertEquals('null_name', $section->name);
 | 
        
           |  |  | 901 |   | 
        
           |  |  | 902 |         $sectioninfo = get_fast_modinfo($course->id)->get_section_info_by_id($section->id);
 | 
        
           |  |  | 903 |         $this->assertEquals('null_name', $sectioninfo->name);
 | 
        
           |  |  | 904 |     }
 | 
        
           | 1441 | ariadna | 905 |   | 
        
           |  |  | 906 |     /**
 | 
        
           |  |  | 907 |      * Test that the position of a new section in a course with deleghated sections.
 | 
        
           |  |  | 908 |      * @covers ::create
 | 
        
           |  |  | 909 |      * @covers ::create_delegated
 | 
        
           |  |  | 910 |      */
 | 
        
           |  |  | 911 |     public function test_create_position(): void {
 | 
        
           |  |  | 912 |         global $DB, $CFG;
 | 
        
           |  |  | 913 |         $this->resetAfterTest();
 | 
        
           |  |  | 914 |   | 
        
           |  |  | 915 |         require_once($CFG->libdir . '/tests/fixtures/sectiondelegatetest.php');
 | 
        
           |  |  | 916 |   | 
        
           |  |  | 917 |         $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 1]);
 | 
        
           |  |  | 918 |   | 
        
           |  |  | 919 |         $section1 = get_fast_modinfo($course->id)->get_section_info(1);
 | 
        
           |  |  | 920 |   | 
        
           |  |  | 921 |         $sectionactions = new sectionactions($course);
 | 
        
           |  |  | 922 |         $delegatedsection1 = $sectionactions->create_delegated('test_component', 1);
 | 
        
           |  |  | 923 |         $delegatedsection2 = $sectionactions->create_delegated('test_component', 2);
 | 
        
           |  |  | 924 |   | 
        
           |  |  | 925 |         $this->assertEquals(2, $delegatedsection1->section);
 | 
        
           |  |  | 926 |         $this->assertEquals(3, $delegatedsection2->section);
 | 
        
           |  |  | 927 |   | 
        
           |  |  | 928 |         // Create some regular sections with zero and none param.
 | 
        
           |  |  | 929 |         $newsection1 = $sectionactions->create(0);
 | 
        
           |  |  | 930 |         $newsection2 = $sectionactions->create();
 | 
        
           |  |  | 931 |   | 
        
           |  |  | 932 |         $this->assertEquals(2, $newsection1->section);
 | 
        
           |  |  | 933 |         $this->assertEquals(3, $newsection2->section);
 | 
        
           |  |  | 934 |   | 
        
           |  |  | 935 |         // Check the section order.
 | 
        
           |  |  | 936 |         $section = $sectioninfo = get_fast_modinfo($course->id)->get_section_info_all();
 | 
        
           |  |  | 937 |         $this->assertEquals($section1->id, $section[1]->id);
 | 
        
           |  |  | 938 |         $this->assertEquals($newsection1->id, $section[2]->id);
 | 
        
           |  |  | 939 |         $this->assertEquals($newsection2->id, $section[3]->id);
 | 
        
           |  |  | 940 |         $this->assertEquals($delegatedsection1->id, $section[4]->id);
 | 
        
           |  |  | 941 |         $this->assertEquals($delegatedsection2->id, $section[5]->id);
 | 
        
           |  |  | 942 |     }
 | 
        
           | 1 | efrain | 943 | }
 |