Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
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
/**
18
 * Course related unit tests
19
 *
20
 * @package    core_course
21
 * @copyright  2014 Marina Glancy
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 * @covers     \core_courseformat\base
24
 * @coversDefaultClass \core_courseformat\base
25
 */
1441 ariadna 26
final class base_test extends advanced_testcase {
1 efrain 27
 
28
    /**
29
     * Setup to ensure that fixtures are loaded.
30
     */
31
    public static function setupBeforeClass(): void {
32
        global $CFG;
33
        require_once($CFG->dirroot . '/course/lib.php');
34
        require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php');
35
        require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_state.php');
36
        require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_invalidoutput.php');
37
    }
38
 
39
    /**
40
     * Tests the save and load functionality.
41
     *
42
     * @author Jason den Dulk
43
     */
11 efrain 44
    public function test_courseformat_saveandload(): void {
1 efrain 45
        $this->resetAfterTest();
46
 
47
        $courseformatoptiondata = (object) [
48
            "hideoddsections" => 1,
49
            'summary_editor' => [
50
                'text' => '<p>Somewhere over the rainbow</p><p>The <b>quick</b> brown fox jumpos over the lazy dog.</p>',
51
                'format' => 1
52
            ]
53
        ];
54
        $generator = $this->getDataGenerator();
55
        $course1 = $generator->create_course(array('format' => 'theunittest'));
56
        $this->assertEquals('theunittest', $course1->format);
57
        course_create_sections_if_missing($course1, array(0, 1));
58
 
59
        $courseformat = course_get_format($course1);
60
        $courseformat->update_course_format_options($courseformatoptiondata);
61
 
62
        $savedcourseformatoptiondata = $courseformat->get_format_options();
63
 
64
        $this->assertEqualsCanonicalizing($courseformatoptiondata, (object) $savedcourseformatoptiondata);
65
    }
66
 
11 efrain 67
    public function test_available_hook(): void {
1 efrain 68
        global $DB;
69
        $this->resetAfterTest();
70
 
71
        // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'theunittest'.
72
        $generator = $this->getDataGenerator();
73
        $course1 = $generator->create_course(array('format' => 'theunittest'));
74
        $this->assertEquals('theunittest', $course1->format);
75
        course_create_sections_if_missing($course1, array(0, 1));
76
        $assign0 = $generator->create_module('assign', array('course' => $course1, 'section' => 0));
77
        $assign1 = $generator->create_module('assign', array('course' => $course1, 'section' => 1));
78
        $assign2 = $generator->create_module('assign', array('course' => $course1, 'section' => 0, 'visible' => 0));
79
 
80
        // Create a courseoverview role based on the student role.
81
        $roleattr = array('name' => 'courseoverview', 'shortname' => 'courseoverview', 'archetype' => 'student');
82
        $generator->create_role($roleattr);
83
 
84
        // Create user student, editingteacher, teacher and courseoverview.
85
        $student = $generator->create_user();
86
        $teacher = $generator->create_user();
87
        $editingteacher = $generator->create_user();
88
        $courseoverviewuser = $generator->create_user();
89
 
90
        // Enrol users into their roles.
91
        $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
92
        $generator->enrol_user($student->id, $course1->id, $roleids['student']);
93
        $generator->enrol_user($teacher->id, $course1->id, $roleids['teacher']);
94
        $generator->enrol_user($editingteacher->id, $course1->id, $roleids['editingteacher']);
95
        $generator->enrol_user($courseoverviewuser->id, $course1->id, $roleids['courseoverview']);
96
 
97
        // Remove the ignoreavailabilityrestrictions from the teacher role.
98
        role_change_permission($roleids['teacher'], context_system::instance(0),
99
                'moodle/course:ignoreavailabilityrestrictions', CAP_PREVENT);
100
 
101
        // Allow the courseoverview role to ingore available restriction.
102
        role_change_permission($roleids['courseoverview'], context_system::instance(0),
103
                'moodle/course:ignoreavailabilityrestrictions', CAP_ALLOW);
104
 
105
        // Make sure that initially both sections and both modules are available and visible for a student.
106
        $modinfostudent = get_fast_modinfo($course1, $student->id);
107
        $this->assertTrue($modinfostudent->get_section_info(1)->available);
108
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available);
109
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible);
110
        $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->available);
111
        $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->uservisible);
112
        $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible);
113
 
114
        // Set 'hideoddsections' for the course to 1.
115
        // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher.
116
        $data = (object)array('id' => $course1->id, 'hideoddsections' => 1);
117
        course_get_format($course1)->update_course_format_options($data);
118
        $modinfostudent = get_fast_modinfo($course1, $student->id);
119
        $this->assertFalse($modinfostudent->get_section_info(1)->available);
120
        $this->assertEmpty($modinfostudent->get_section_info(1)->availableinfo);
121
        $this->assertFalse($modinfostudent->get_section_info(1)->uservisible);
122
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available);
123
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible);
124
        $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available);
125
        $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible);
126
        $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible);
127
 
128
        $modinfoteacher = get_fast_modinfo($course1, $teacher->id);
129
        $this->assertFalse($modinfoteacher->get_section_info(1)->available);
130
        $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo);
131
        $this->assertFalse($modinfoteacher->get_section_info(1)->uservisible);
132
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available);
133
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible);
134
        $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available);
135
        $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->uservisible);
136
        $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->available);
137
        $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible);
138
 
139
        $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id);
140
        $this->assertFalse($modinfoteacher->get_section_info(1)->available);
141
        $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo);
142
        $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible);
143
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available);
144
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible);
145
        $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available);
146
        $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible);
147
        $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible);
148
 
149
        $modinfocourseoverview = get_fast_modinfo($course1, $courseoverviewuser->id);
150
        $this->assertFalse($modinfocourseoverview->get_section_info(1)->available);
151
        $this->assertEmpty($modinfocourseoverview->get_section_info(1)->availableinfo);
152
        $this->assertTrue($modinfocourseoverview->get_section_info(1)->uservisible);
153
        $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->available);
154
        $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->uservisible);
155
        $this->assertFalse($modinfocourseoverview->get_cm($assign1->cmid)->available);
156
        $this->assertTrue($modinfocourseoverview->get_cm($assign1->cmid)->uservisible);
157
        $this->assertFalse($modinfocourseoverview->get_cm($assign2->cmid)->uservisible);
158
 
159
        // Set 'hideoddsections' for the course to 2.
160
        // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher.
161
        // Property availableinfo will be not empty.
162
        $data = (object)array('id' => $course1->id, 'hideoddsections' => 2);
163
        course_get_format($course1)->update_course_format_options($data);
164
        $modinfostudent = get_fast_modinfo($course1, $student->id);
165
        $this->assertFalse($modinfostudent->get_section_info(1)->available);
166
        $this->assertNotEmpty($modinfostudent->get_section_info(1)->availableinfo);
167
        $this->assertFalse($modinfostudent->get_section_info(1)->uservisible);
168
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available);
169
        $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible);
170
        $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available);
171
        $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible);
172
 
173
        $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id);
174
        $this->assertFalse($modinfoteacher->get_section_info(1)->available);
175
        $this->assertNotEmpty($modinfoteacher->get_section_info(1)->availableinfo);
176
        $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible);
177
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available);
178
        $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible);
179
        $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available);
180
        $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible);
181
    }
182
 
183
    /**
184
     * Test for supports_news() with a course format plugin that doesn't define 'news_items' in default blocks.
185
     */
11 efrain 186
    public function test_supports_news(): void {
1 efrain 187
        $this->resetAfterTest();
188
        $format = course_get_format((object)['format' => 'testformat']);
189
        $this->assertFalse($format->supports_news());
190
    }
191
 
192
    /**
193
     * Test for supports_news() for old course format plugins that defines 'news_items' in default blocks.
194
     */
11 efrain 195
    public function test_supports_news_legacy(): void {
1 efrain 196
        $this->resetAfterTest();
197
        $format = course_get_format((object)['format' => 'testlegacy']);
198
        $this->assertTrue($format->supports_news());
199
    }
200
 
201
    /**
202
     * Test for get_view_url().
203
     *
204
     * @covers ::get_view_url
205
     */
206
    public function test_get_view_url(): void {
207
        global $CFG;
208
        $this->resetAfterTest();
209
 
210
        // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'testformat'.
211
        // This will allow us to test the default implementation of get_view_url.
212
        $generator = $this->getDataGenerator();
213
        $course1 = $generator->create_course(array('format' => 'testformat'));
214
        course_create_sections_if_missing($course1, array(0, 1));
215
 
216
        $data = (object)['id' => $course1->id];
217
        $format = course_get_format($course1);
218
        $format->update_course_format_options($data);
219
 
220
        // In page.
221
        $this->assertNotEmpty($format->get_view_url(null));
222
        $this->assertNotEmpty($format->get_view_url(0));
223
        $this->assertNotEmpty($format->get_view_url(1));
224
 
225
        // Navigation.
226
        $this->assertStringContainsString('course/view.php', $format->get_view_url(0));
227
        $this->assertStringContainsString('course/view.php', $format->get_view_url(1));
228
        $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['navigation' => 1]));
229
        $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['navigation' => 1]));
230
        // When sr parameter is defined, the section.php page should be returned.
231
        $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 1]));
232
        $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 1]));
233
        $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 0]));
234
        $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 0]));
235
 
236
        // Expand section.
237
        // The current course format $format uses the format 'testformat' which does not use sections.
238
        // Thus, the 'expanded' parameter does not do anything.
239
        $viewurl = $format->get_view_url(1);
240
        $this->assertNull($viewurl->get_param('expandsection'));
241
        $viewurl = $format->get_view_url(1, ['expanded' => 1]);
242
        $this->assertNull($viewurl->get_param('expandsection'));
243
        $viewurl = $format->get_view_url(1, ['expanded' => 0]);
244
        $this->assertNull($viewurl->get_param('expandsection'));
245
        // We now use a course format which uses sections.
246
        $course2 = $generator->create_course(['format' => 'testformatsections']);
247
        course_create_sections_if_missing($course1, [0, 2]);
248
        $formatwithsections = course_get_format($course2);
249
        $viewurl = $formatwithsections->get_view_url(2);
250
        $this->assertEquals(2, $viewurl->get_param('expandsection'));
251
        $viewurl = $formatwithsections->get_view_url(2, ['expanded' => 1]);
252
        $this->assertEquals(2, $viewurl->get_param('expandsection'));
253
        $viewurl = $formatwithsections->get_view_url(2, ['expanded' => 0]);
254
        $this->assertNull($viewurl->get_param('expandsection'));
255
    }
256
 
257
    /**
258
     * Test for get_output_classname method.
259
     *
260
     * @dataProvider get_output_classname_provider
261
     * @param string $find the class to find
262
     * @param string $result the expected result classname
263
     * @param bool $exception if the method will raise an exception
264
     */
11 efrain 265
    public function test_get_output_classname($find, $result, $exception): void {
1 efrain 266
        $this->resetAfterTest();
267
 
268
        $course = $this->getDataGenerator()->create_course(['format' => 'theunittest']);
269
        $courseformat = course_get_format($course);
270
 
271
        if ($exception) {
272
            $this->expectException(coding_exception::class);
273
        }
274
 
275
        $courseclass = $courseformat->get_output_classname($find);
276
        $this->assertEquals($result, $courseclass);
277
    }
278
 
279
    /**
280
     * Data provider for test_get_output_classname.
281
     *
282
     * @return array the testing scenarios
283
     */
1441 ariadna 284
    public static function get_output_classname_provider(): array {
1 efrain 285
        return [
286
            'overridden class' => [
287
                'find' => 'state\\course',
288
                'result' => 'format_theunittest\\output\\courseformat\\state\\course',
289
                'exception' => false,
290
            ],
291
            'original class' => [
292
                'find' => 'state\\section',
293
                'result' => 'core_courseformat\\output\\local\\state\\section',
294
                'exception' => false,
295
            ],
296
            'invalid overridden class' => [
297
                'find' => 'state\\invalidoutput',
298
                'result' => '',
299
                'exception' => true,
300
            ],
301
        ];
302
    }
303
 
304
    /**
305
     * Test for the default delete format data behaviour.
306
     *
307
     * @covers ::get_sections_preferences
308
     */
11 efrain 309
    public function test_get_sections_preferences(): void {
1 efrain 310
        $this->resetAfterTest();
311
        $generator = $this->getDataGenerator();
312
        $course = $generator->create_course();
313
        $user = $generator->create_and_enrol($course, 'student');
314
 
315
        // Create fake preferences generated by the frontend js module.
316
        $data = (object)[
317
            'pref1' => [1,2],
318
            'pref2' => [1],
319
        ];
320
        set_user_preference('coursesectionspreferences_' . $course->id, json_encode($data), $user->id);
321
 
322
        $format = course_get_format($course);
323
 
324
        // Load data from user 1.
325
        $this->setUser($user);
326
        $preferences = $format->get_sections_preferences();
327
 
328
        $this->assertEquals(
329
            (object)['pref1' => true, 'pref2' => true],
330
            $preferences[1]
331
        );
332
        $this->assertEquals(
333
            (object)['pref1' => true],
334
            $preferences[2]
335
        );
336
    }
337
 
338
    /**
339
     * Test for the default delete format data behaviour.
340
     *
341
     * @covers ::set_sections_preference
342
     */
11 efrain 343
    public function test_set_sections_preference(): void {
1 efrain 344
        $this->resetAfterTest();
345
        $generator = $this->getDataGenerator();
346
        $course = $generator->create_course();
347
        $user = $generator->create_and_enrol($course, 'student');
348
 
349
        $format = course_get_format($course);
350
        $this->setUser($user);
351
 
352
        // Load data from user 1.
353
        $format->set_sections_preference('pref1', [1, 2]);
354
        $format->set_sections_preference('pref2', [1]);
355
        $format->set_sections_preference('pref3', []);
356
 
357
        $preferences = $format->get_sections_preferences();
358
        $this->assertEquals(
359
            (object)['pref1' => true, 'pref2' => true],
360
            $preferences[1]
361
        );
362
        $this->assertEquals(
363
            (object)['pref1' => true],
364
            $preferences[2]
365
        );
366
    }
367
 
368
    /**
369
     * Test add_section_preference_ids() method.
370
     *
371
     * @covers \core_courseformat\base::persist_to_user_preference
372
     */
373
    public function test_add_section_preference_ids(): void {
374
        $this->resetAfterTest();
375
        // Create initial data.
376
        $generator = $this->getDataGenerator();
377
        $course = $generator->create_course();
378
        $user = $generator->create_and_enrol($course);
379
        // Get the course format.
380
        $format = course_get_format($course);
381
        // Login as the user.
382
        $this->setUser($user);
383
 
384
        // Add section preference ids.
385
        $format->add_section_preference_ids('pref1', [1, 2]);
386
        $format->add_section_preference_ids('pref1', [3]);
387
        $format->add_section_preference_ids('pref2', [1]);
388
 
389
        // Get section preferences.
390
        $sectionpreferences = $format->get_sections_preferences_by_preference();
391
        $this->assertCount(3, $sectionpreferences['pref1']);
392
        $this->assertContains(1, $sectionpreferences['pref1']);
393
        $this->assertContains(2, $sectionpreferences['pref1']);
394
        $this->assertContains(3, $sectionpreferences['pref1']);
395
        $this->assertCount(1, $sectionpreferences['pref2']);
396
        $this->assertContains(1, $sectionpreferences['pref1']);
397
    }
398
 
399
    /**
400
     * Test remove_section_preference_ids() method.
401
     *
402
     * @covers \core_courseformat\base::persist_to_user_preference
403
     */
404
    public function test_remove_section_preference_ids(): void {
405
        $this->resetAfterTest();
406
        // Create initial data.
407
        $generator = $this->getDataGenerator();
408
        $course = $generator->create_course();
409
        $user = $generator->create_and_enrol($course);
410
        // Get the course format.
411
        $format = course_get_format($course);
412
        // Login as the user.
413
        $this->setUser($user);
414
        // Set initial preferences.
415
        $format->set_sections_preference('pref1', [1, 2, 3]);
416
        $format->set_sections_preference('pref2', [1]);
417
 
418
        // Remove section with id = 3 out of the pref1.
419
        $format->remove_section_preference_ids('pref1', [3]);
420
        // Get section preferences.
421
        $sectionpreferences = $format->get_sections_preferences_by_preference();
422
        $this->assertCount(2, $sectionpreferences['pref1']);
423
        $this->assertCount(1, $sectionpreferences['pref2']);
424
 
425
        // Remove section with id = 2 out of the pref1.
426
        $format->remove_section_preference_ids('pref1', [2]);
427
        // Remove section with id = 1 out of the pref2.
428
        $format->remove_section_preference_ids('pref2', [1]);
429
        // Get section preferences.
430
        $sectionpreferences = $format->get_sections_preferences_by_preference();
431
        $this->assertCount(1, $sectionpreferences['pref1']);
432
        $this->assertEmpty($sectionpreferences['pref2']);
433
    }
434
 
435
    /**
436
     * Test that retrieving last section number for a course
437
     *
438
     * @covers ::get_last_section_number
439
     */
440
    public function test_get_last_section_number(): void {
441
        global $DB;
442
 
443
        $this->resetAfterTest();
444
 
445
        // Course with two additional sections.
446
        $courseone = $this->getDataGenerator()->create_course(['numsections' => 2]);
447
        $this->assertEquals(2, course_get_format($courseone)->get_last_section_number());
448
 
449
        // Course without additional sections, section zero is the "default" section that always exists.
450
        $coursetwo = $this->getDataGenerator()->create_course(['numsections' => 0]);
451
        $this->assertEquals(0, course_get_format($coursetwo)->get_last_section_number());
452
 
453
        // Course without additional sections, manually remove section zero, as "course_delete_section" prevents that. This
454
        // simulates course data integrity issues that previously triggered errors.
455
        $coursethree = $this->getDataGenerator()->create_course(['numsections' => 0]);
456
        $DB->delete_records('course_sections', ['course' => $coursethree->id, 'section' => 0]);
457
 
458
        $this->assertEquals(-1, course_get_format($coursethree)->get_last_section_number());
459
    }
460
 
461
    /**
462
     * Test for the default delete format data behaviour.
463
     *
464
     * @covers ::delete_format_data
465
     * @dataProvider delete_format_data_provider
466
     * @param bool $usehook if it should use course_delete to trigger $format->delete_format_data as a hook
467
     */
11 efrain 468
    public function test_delete_format_data(bool $usehook): void {
1 efrain 469
        global $DB;
470
 
471
        $this->resetAfterTest();
472
 
473
        $generator = $this->getDataGenerator();
474
        $course = $generator->create_course();
475
        course_create_sections_if_missing($course, [0, 1]);
476
        $user = $generator->create_and_enrol($course, 'student');
477
 
478
        // Create a coursesectionspreferences_XX preference.
479
        $key = 'coursesectionspreferences_' . $course->id;
480
        $fakevalue = 'No dark sarcasm in the classroom';
481
        set_user_preference($key, $fakevalue, $user->id);
482
        $this->assertEquals(
483
            $fakevalue,
484
            $DB->get_field('user_preferences', 'value', ['name' => $key, 'userid' => $user->id])
485
        );
486
 
487
        // Create another random user preference.
488
        $key2 = 'somepreference';
489
        $fakevalue2 = "All in all it's just another brick in the wall";
490
        set_user_preference($key2, $fakevalue2, $user->id);
491
        $this->assertEquals(
492
            $fakevalue2,
493
            $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id])
494
        );
495
 
496
        if ($usehook) {
497
            delete_course($course, false);
498
        } else {
499
            $format = course_get_format($course);
500
            $format->delete_format_data();
501
        }
502
 
503
        // Check which the preferences exists.
504
        $this->assertFalse(
505
            $DB->record_exists('user_preferences', ['name' => $key, 'userid' => $user->id])
506
        );
507
        set_user_preference($key2, $fakevalue2, $user->id);
508
        $this->assertEquals(
509
            $fakevalue2,
510
            $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id])
511
        );
512
    }
513
 
514
    /**
515
     * Data provider for test_delete_format_data.
516
     *
517
     * @return array the testing scenarios
518
     */
1441 ariadna 519
    public static function delete_format_data_provider(): array {
1 efrain 520
        return [
521
            'direct call' => [
522
                'usehook' => false
523
            ],
524
            'use hook' => [
525
                'usehook' => true,
526
            ]
527
        ];
528
    }
529
 
530
    /**
531
     * Test duplicate_section()
532
     * @covers ::duplicate_section
533
     */
11 efrain 534
    public function test_duplicate_section(): void {
1 efrain 535
        global $DB;
536
 
537
        $this->setAdminUser();
538
        $this->resetAfterTest();
539
 
540
        $generator = $this->getDataGenerator();
541
        $course = $generator->create_course();
542
        $format = course_get_format($course);
543
 
1441 ariadna 544
        $originalsection = $DB->get_record('course_sections', ['course' => $course->id, 'section' => 0], '*', MUST_EXIST);
1 efrain 545
        $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]);
546
        $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]);
547
        $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]);
1441 ariadna 548
        $generator->create_module('qbank', ['course' => $course, 'section' => $originalsection->section]);
1 efrain 549
 
550
        $originalmodcount = $DB->count_records('course_modules', ['course' => $course->id, 'section' => $originalsection->id]);
1441 ariadna 551
        $this->assertEquals(4, $originalmodcount);
1 efrain 552
 
553
        $modinfo = get_fast_modinfo($course);
554
        $sectioninfo = $modinfo->get_section_info($originalsection->section, MUST_EXIST);
555
 
556
        $newsection = $format->duplicate_section($sectioninfo);
557
 
558
        // Verify properties are the same.
559
        foreach ($originalsection as $prop => $value) {
560
            if ($prop == 'id' || $prop == 'sequence' || $prop == 'section' || $prop == 'timemodified') {
561
                continue;
562
            }
563
            $this->assertEquals($value, $newsection->$prop);
564
        }
565
 
566
        $newmodcount = $DB->count_records('course_modules', ['course' => $course->id, 'section' => $newsection->id]);
1441 ariadna 567
        $modinfo = course_modinfo::instance($course);
568
        $qbankinstances = $modinfo->get_instances_of('qbank');
569
        $this->assertCount(1, $qbankinstances);
570
        $this->assertEquals($originalmodcount - 1, $newmodcount);
1 efrain 571
    }
572
 
573
    /**
1441 ariadna 574
     * Test duplicate_section() with delegated section
575
     * @covers     ::duplicate_section
576
     */
577
    public function test_duplicate_section_with_delegated_sections(): void {
578
        global $DB;
579
 
580
        $this->setAdminUser();
581
        $this->resetAfterTest();
582
        // Add subsection.
583
        $manager = \core_plugin_manager::resolve_plugininfo_class('mod');
584
        $manager::enable_plugin('subsection', 1);
585
        $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 1]);
586
        $subsection1 = $this->getDataGenerator()->create_module(
587
            'subsection', ['course' => $course, 'section' => 1, 'name' => 'subsection1']);
588
        $subsection2 = $this->getDataGenerator()->create_module(
589
            'subsection', ['course' => $course, 'section' => 1, 'name' => 'subsection2']);
590
        $format = course_get_format($course);
591
 
592
        $modinfo = get_fast_modinfo($course);
593
        $sectioninfo = $modinfo->get_section_info(1, MUST_EXIST);
594
        $originalsectioncount = $DB->count_records('course_sections', ['course' => $course->id]);
595
        $this->assertEquals(4, $originalsectioncount);
596
 
597
        $originalsection = $DB->get_record('course_sections',
598
            ['course' => $course->id, 'section' => 0],
599
            '*',
600
            MUST_EXIST);
601
        $newsection = $format->duplicate_section($sectioninfo);
602
        foreach ($originalsection as $prop => $value) {
603
            if ($prop == 'id' || $prop == 'sequence' || $prop == 'section' || $prop == 'timemodified') {
604
                continue;
605
            }
606
            $this->assertEquals($value, $newsection->$prop);
607
        }
608
        $sectioncount = $DB->count_records('course_sections', ['course' => $course->id]);
609
        $this->assertEquals(7, $sectioncount);
610
    }
611
 
612
    /**
1 efrain 613
     * Test for the default delete format data behaviour.
614
     *
615
     * @covers ::get_format_string
616
     * @dataProvider get_format_string_provider
617
     * @param string $key the string key
618
     * @param string|null $data any string data
619
     * @param array|null $expectedstring the expected string (null for exception)
620
     * @param string $courseformat the course format
621
     */
622
    public function test_get_format_string(
623
        string $key,
624
        ?string $data,
625
        ?array $expectedstring,
626
        string $courseformat = 'topics'
627
    ): void {
628
        global $DB;
629
 
630
        $this->resetAfterTest();
631
 
632
        $generator = $this->getDataGenerator();
633
        $course = $generator->create_course(['format' => $courseformat]);
634
 
635
        if ($expectedstring) {
636
            $expected = get_string($expectedstring[0], $expectedstring[1], $expectedstring[2]);
637
        } else {
638
            $this->expectException(\coding_exception::class);
639
        }
640
        $format = course_get_format($course);
641
        $result = $format->get_format_string($key, $data);
642
        $this->assertEquals($expected, $result);
643
    }
644
 
645
    /**
646
     * Data provider for test_get_format_string.
647
     *
648
     * @return array the testing scenarios
649
     */
1441 ariadna 650
    public static function get_format_string_provider(): array {
1 efrain 651
        return [
652
            'Existing in format lang' => [
653
                'key' => 'addsection',
654
                'data' => null,
655
                'expectedstring' => ['addsection', 'format_weeks', null],
656
                'courseformat' => 'weeks',
657
            ],
658
            'Not existing in format lang' => [
659
                'key' => 'bulkedit',
660
                'data' => null,
661
                'expectedstring' => ['bulkedit', 'core_courseformat', null],
662
            ],
663
            'Existing in format lang with data' => [
664
                'key' => 'section_highlight_feedback',
665
                'data' => 'Example',
666
                'expectedstring' => ['section_highlight_feedback', 'format_topics', 'Example'],
667
            ],
668
            'Not existing in format lang with data' => [
669
                'key' => 'bulkselection',
670
                'data' => 'X',
671
                'expectedstring' => ['bulkselection', 'core_courseformat', 'X'],
672
            ],
673
            'Non existing string' => [
674
                'key' => '%&non_existing_string_in_lang_files$%@#',
675
                'data' => null,
676
                'expectedstring' => null,
677
            ],
678
        ];
679
    }
680
 
681
    /**
682
     * Test for the move_section_after method.
683
     *
684
     * @covers ::move_section_after
685
     * @dataProvider move_section_after_provider
686
     * @param string $movesection the reference of the section to move
687
     * @param string $destination the reference of the destination section
688
     * @param string[] $order the references of the final section order
689
     */
11 efrain 690
    public function test_move_section_after(string $movesection, string $destination, array $order): void {
1 efrain 691
        global $DB;
692
 
693
        $this->resetAfterTest();
694
 
695
        $generator = $this->getDataGenerator();
696
        $course = $generator->create_course();
697
        course_create_sections_if_missing($course, [0, 1, 2, 3, 4, 5]);
698
 
699
        $format = course_get_format($course);
700
        $modinfo = $format->get_modinfo();
701
        $sectionsinfo = $modinfo->get_section_info_all();
702
 
703
        $references = [];
704
        foreach ($sectionsinfo as $section) {
705
            $references["section{$section->section}"] = $section;
706
        }
707
 
708
        $result = $format->move_section_after(
709
            $references[$movesection],
710
            $references[$destination]
711
        );
712
        $this->assertEquals(true, $result);
713
        // Check the updated course section list.
714
        $modinfo = $format->get_modinfo();
715
        $sectionsinfo = $modinfo->get_section_info_all();
716
        $this->assertCount(count($order), $sectionsinfo);
717
        foreach ($sectionsinfo as $key => $section) {
718
            $sectionreference = $order[$key];
719
            $oldinfo = $references[$sectionreference];
720
            $this->assertEquals($oldinfo->id, $section->id);
721
        }
722
    }
723
 
724
    /**
725
     * Data provider for test_move_section_after.
726
     *
727
     * @return array the testing scenarios
728
     */
1441 ariadna 729
    public static function move_section_after_provider(): array {
1 efrain 730
        return [
731
            'Move top' => [
732
                'movesection' => 'section3',
733
                'destination' => 'section0',
734
                'order' => [
735
                    'section0',
736
                    'section3',
737
                    'section1',
738
                    'section2',
739
                    'section4',
740
                    'section5',
741
                ],
742
            ],
743
            'Move up' => [
744
                'movesection' => 'section3',
745
                'destination' => 'section1',
746
                'order' => [
747
                    'section0',
748
                    'section1',
749
                    'section3',
750
                    'section2',
751
                    'section4',
752
                    'section5',
753
                ],
754
            ],
755
            'Do not move' => [
756
                'movesection' => 'section3',
757
                'destination' => 'section2',
758
                'order' => [
759
                    'section0',
760
                    'section1',
761
                    'section2',
762
                    'section3',
763
                    'section4',
764
                    'section5',
765
                ],
766
            ],
767
            'Same position' => [
768
                'movesection' => 'section3',
769
                'destination' => 'section3',
770
                'order' => [
771
                    'section0',
772
                    'section1',
773
                    'section2',
774
                    'section3',
775
                    'section4',
776
                    'section5',
777
                ],
778
            ],
779
            'Move down' => [
780
                'movesection' => 'section3',
781
                'destination' => 'section4',
782
                'order' => [
783
                    'section0',
784
                    'section1',
785
                    'section2',
786
                    'section4',
787
                    'section3',
788
                    'section5',
789
                ],
790
            ],
791
            'Move bottom' => [
792
                'movesection' => 'section3',
793
                'destination' => 'section5',
794
                'order' => [
795
                    'section0',
796
                    'section1',
797
                    'section2',
798
                    'section4',
799
                    'section5',
800
                    'section3',
801
                ],
802
            ],
803
        ];
804
    }
805
 
806
    /**
807
     * Test for the get_non_ajax_cm_action_url method.
808
     *
809
     * @covers ::get_non_ajax_cm_action_url
810
     * @dataProvider get_non_ajax_cm_action_url_provider
811
     * @param string $action the ajax action name
812
     * @param string $expectedparam the expected param to check
813
     * @param string $exception if an exception is expected
814
     */
11 efrain 815
    public function test_get_non_ajax_cm_action_url(string $action, string $expectedparam, bool $exception): void {
1 efrain 816
        global $DB;
817
 
818
        $this->resetAfterTest();
819
 
820
        $generator = $this->getDataGenerator();
821
        $course = $generator->create_course();
822
        $assign0 = $generator->create_module('assign', array('course' => $course, 'section' => 0));
823
 
824
        $format = course_get_format($course);
825
        $modinfo = $format->get_modinfo();
826
        $cminfo = $modinfo->get_cm($assign0->cmid);
827
 
828
        if ($exception) {
829
            $this->expectException(\coding_exception::class);
830
        }
831
        $result = $format->get_non_ajax_cm_action_url($action, $cminfo);
1441 ariadna 832
        if (!$exception) {
833
            $this->assertDebuggingCalled();
834
        }
835
        $this->assertEquals($assign0->cmid, $result->param('id'));
1 efrain 836
    }
837
 
838
    /**
839
     * Data provider for test_get_non_ajax_cm_action_url.
840
     *
841
     * @return array the testing scenarios
842
     */
1441 ariadna 843
    public static function get_non_ajax_cm_action_url_provider(): array {
1 efrain 844
        return [
845
            'duplicate' => [
846
                'action' => 'cmDuplicate',
847
                'expectedparam' => 'duplicate',
848
                'exception' => false,
849
            ],
850
            'hide' => [
851
                'action' => 'cmHide',
852
                'expectedparam' => 'hide',
853
                'exception' => false,
854
            ],
855
            'show' => [
856
                'action' => 'cmShow',
857
                'expectedparam' => 'show',
858
                'exception' => false,
859
            ],
860
            'stealth' => [
861
                'action' => 'cmStealth',
862
                'expectedparam' => 'stealth',
863
                'exception' => false,
864
            ],
865
            'delete' => [
866
                'action' => 'cmDelete',
867
                'expectedparam' => 'delete',
868
                'exception' => false,
869
            ],
870
            'non-existent' => [
871
                'action' => 'nonExistent',
872
                'expectedparam' => '',
873
                'exception' => true,
874
            ],
875
        ];
876
    }
877
 
878
    /**
879
     * Test get_required_jsfiles().
880
     *
881
     * @covers ::get_required_jsfiles
882
     */
883
    public function test_get_required_jsfiles(): void {
884
        $this->resetAfterTest();
885
 
886
        $generator = $this->getDataGenerator();
887
 
888
        $course = $generator->create_course(['format' => 'testformat']);
889
        $format = course_get_format($course);
890
        $this->assertEmpty($format->get_required_jsfiles());
891
    }
892
 
893
    /**
894
     * Test set_sectionid().
895
     *
896
     * @covers ::set_sectionid
897
     * @covers ::get_sectionid
898
     * @covers ::get_sectionnum
899
     */
900
    public function test_set_sectionid(): void {
901
        $this->resetAfterTest();
902
 
903
        $generator = $this->getDataGenerator();
904
        $course = $generator->create_course(['numsections' => 2]);
905
        $format = course_get_format($course);
906
 
907
        // No section.
908
        $this->assertNull($format->get_sectionid());
909
        $this->assertNull($format->get_sectionnum());
910
 
911
        // Valid section.
912
        $sectionnum = 1;
913
        $modinfo = get_fast_modinfo($course);
914
        $sectioninfo = $modinfo->get_section_info($sectionnum);
915
        $sectionid = $sectioninfo->id;
916
        $format->set_sectionid($sectionid);
917
        $this->assertEquals($sectionid, $format->get_sectionid());
918
        $this->assertEquals($sectionnum, $format->get_sectionnum());
919
 
920
        // Null section.
921
        $format->set_sectionid(null);
922
        $this->assertNull($format->get_sectionid());
923
        $this->assertNull($format->get_sectionnum());
924
 
925
        // Invalid section.
926
        $this->expectException(\coding_exception::class);
927
        $format->set_sectionid(-1);
928
    }
929
 
930
    /**
931
     * Test set_sectionnum().
932
     *
933
     * @dataProvider set_sectionnum_provider
934
     * @covers ::set_sectionnum
935
     * @param int|null $sectionnum The section number
936
     * @param bool $nullexpected If null is expected
937
     * @param bool $exceptionexpected If an exception is expected
938
     */
939
    public function test_set_sectionnum(?int $sectionnum, bool $nullexpected = false, bool $exceptionexpected = false): void {
940
        $this->resetAfterTest();
941
 
942
        $generator = $this->getDataGenerator();
943
        $course = $generator->create_course(['numsections' => 2]);
944
        $format = course_get_format($course);
945
 
946
        if ($exceptionexpected) {
947
            $this->expectException(\coding_exception::class);
948
        }
949
        $format->set_sectionnum($sectionnum);
950
        if ($nullexpected) {
951
            $this->assertNull($format->get_sectionid());
952
            $this->assertNull($format->get_sectionnum());
953
        } else {
954
            $this->assertNotNull($format->get_sectionid());
955
            $this->assertNotNull($format->get_sectionnum());
956
        }
957
    }
958
 
959
    /**
960
     * Data provider for test_set_sectionnum.
961
     *
962
     * @return array The testing scenarios
963
     */
964
    public static function set_sectionnum_provider(): array {
965
        return [
966
            'General sectionnumber' => [
967
                'sectionnum' => 0,
968
                'nullexpected' => false,
969
            ],
970
            'Existing sectionnumber' => [
971
                'sectionnum' => 1,
972
                'nullexpected' => false,
973
            ],
974
            'Another existing sectionnumber' => [
975
                'sectionnum' => 2,
976
                'nullexpected' => false,
977
            ],
978
            'Null sectionnumber' => [
979
                'sectionnum' => null,
980
                'nullexpected' => true,
981
            ],
982
            'Invalid sectionnumber' => [
983
                'sectionnum' => 3,
984
                'nullexpected' => true,
985
                'exceptionexpected' => true,
986
            ],
987
            'Another invalid sectionnumber' => [
988
                'sectionnum' => -1,
989
                'nullexpected' => true,
990
                'exceptionexpected' => true,
991
            ],
992
        ];
993
    }
994
 
995
    /**
996
     * Test can_sections_be_removed_from_navigation().
997
     *
998
     * @covers ::can_sections_be_removed_from_navigation
999
     */
1000
    public function test_can_sections_be_removed_from_navigation(): void {
1001
        $this->resetAfterTest();
1002
 
1003
        $generator = $this->getDataGenerator();
1004
 
1005
        $course = $generator->create_course();
1006
        $format = course_get_format($course);
1007
        $this->assertFalse($format->can_sections_be_removed_from_navigation());
1008
 
1009
        $course = $generator->create_course(['format' => 'testformatsections']);
1010
        $format = course_get_format($course);
1011
        $this->assertTrue($format->can_sections_be_removed_from_navigation());
1012
    }
1441 ariadna 1013
 
1014
    public function test_is_section_visible(): void {
1015
        $this->resetAfterTest();
1016
 
1017
        $generator = $this->getDataGenerator();
1018
        $course = $generator->create_course(['format' => 'testformatsections'], ['hiddensections' => 1]);
1019
        course_create_sections_if_missing($course, [0, 1, 2]);
1020
 
1021
        // Students cannot view hidden sections.
1022
        $sectioninfo = get_fast_modinfo($course)->get_section_info(1);
1023
        \core_courseformat\formatactions::section($course)->update($sectioninfo, ['visible' => false]);
1024
 
1025
        $format = course_get_format($course);
1026
 
1027
        // Force max sections to 1 to detect section 2 as orphan.
1028
        $format->forcemaxsections = 1;
1029
 
1030
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
1031
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
1032
 
1033
        $this->setUser($teacher);
1034
        $modinfoteacher = get_fast_modinfo($course, $teacher->id);
1035
        $this->assertTrue($format->is_section_visible($modinfoteacher->get_section_info(0)));
1036
        $this->assertTrue($format->is_section_visible($modinfoteacher->get_section_info(1)));
1037
        $this->assertTrue($format->is_section_visible($modinfoteacher->get_section_info(2)));
1038
 
1039
        $this->setUser($student);
1040
        $modinfostudent = get_fast_modinfo($course, $student->id);
1041
        $this->assertTrue($format->is_section_visible($modinfostudent->get_section_info(0)));
1042
        $this->assertFalse($format->is_section_visible($modinfostudent->get_section_info(1)));
1043
        $this->assertFalse($format->is_section_visible($modinfostudent->get_section_info(2)));
1044
    }
1045
 
1046
    /**
1047
     * Test for the get_generic_section_name method.
1048
     *
1049
     * @covers ::get_generic_section_name
1050
     */
1051
    public function test_get_generic_section_name(): void {
1052
        $this->resetAfterTest();
1053
 
1054
        $generator = $this->getDataGenerator();
1055
        $course1 = $generator->create_course(['format' => 'topics']);
1056
        $course2 = $generator->create_course(['format' => 'theunittest']);
1057
 
1058
        $format = course_get_format($course1);
1059
        $this->assertEquals(
1060
            get_string('sectionname', 'format_topics'),
1061
            $format->get_generic_section_name()
1062
        );
1063
 
1064
        $format = course_get_format($course2);
1065
        $this->assertEquals(
1066
            get_string('section'),
1067
            $format->get_generic_section_name()
1068
        );
1069
    }
1070
 
1071
    /**
1072
     * Test can_sections_be_removed_from_navigation().
1073
     *
1074
     * @covers ::session_cache
1075
     * @covers ::session_cache_reset
1076
     * @covers ::session_cache_reset_all
1077
     * @covers ::invalidate_all_session_caches_for_course
1078
     */
1079
    public function test_session_caches_methods(): void {
1080
        global $DB;
1081
 
1082
        $this->resetAfterTest();
1083
        $generator = $this->getDataGenerator();
1084
 
1085
        $course1 = $generator->create_course(['format' => 'topics']);
1086
        $course2 = $generator->create_course(['format' => 'topics']);
1087
 
1088
        // Force some cacherev to the course.
1089
        $course1->cacherev = 12345;
1090
        $course2->cacherev = 67890;
1091
        $DB->set_field('course', 'cacherev', $course1->cacherev, ['id' => $course1->id]);
1092
        $DB->set_field('course', 'cacherev', $course2->cacherev, ['id' => $course2->id]);
1093
 
1094
        $teacher = $generator->create_and_enrol($course1, 'editingteacher');
1095
        $generator->enrol_user($teacher->id, $course2->id, 'editingteacher');
1096
        $this->setUser($teacher);
1097
 
1098
        // The cache key uses time() as hash. To not wait a second between calls we fake an initial value.
1099
        $statecache = cache::make('core', 'courseeditorstate');
1100
        $statecache->set($course1->id, $course1->cacherev . '_11111');
1101
        $statecache->set($course2->id, $course2->cacherev . '_22222');
1102
 
1103
        $course1cachekey = \core_courseformat\base::session_cache($course1);
1104
 
1105
        // Validate the method returns the same value when called twice.
1106
        $course1cachekeyagain = \core_courseformat\base::session_cache($course1);
1107
        $this->assertEquals($course1cachekey, $course1cachekeyagain);
1108
 
1109
        // Validate other course has a diferent cache key.
1110
        $course2cachekey = \core_courseformat\base::session_cache($course2);
1111
        $this->assertNotEquals($course1cachekey, $course2cachekey);
1112
 
1113
        // Reset the specific course cache.
1114
        \core_courseformat\base::session_cache_reset($course1);
1115
 
1116
        $resetcachekey = \core_courseformat\base::session_cache($course1);
1117
        $this->assertNotEquals($course1cachekey, $resetcachekey);
1118
 
1119
        $reset2cachekey = \core_courseformat\base::session_cache($course2);
1120
        $this->assertEquals($course2cachekey, $reset2cachekey);
1121
 
1122
        // Return to the initial value.
1123
        $statecache->set($course1->id, $course1->cacherev . '_11111');
1124
        $statecache->set($course2->id, $course2->cacherev . '_22222');
1125
 
1126
        // Reset all user course caches.
1127
        \core_courseformat\base::session_cache_reset_all();
1128
 
1129
        $resetallcachekey = \core_courseformat\base::session_cache($course1);
1130
        $this->assertNotEquals($course1cachekey, $resetallcachekey);
1131
 
1132
        $resetall2cachekey = \core_courseformat\base::session_cache($course2);
1133
        $this->assertNotEquals($course2cachekey, $resetall2cachekey);
1134
 
1135
        // Return to the initial value.
1136
        $statecache->set($course1->id, $course1->cacherev . '_11111');
1137
        $statecache->set($course2->id, $course2->cacherev . '_22222');
1138
 
1139
        // Invalidate cache on course 1.
1140
        \core_courseformat\base::invalidate_all_session_caches_for_course($course1);
1141
 
1142
        $invalidatecachekey = \core_courseformat\base::session_cache($course1);
1143
        $this->assertNotEquals($course1cachekey, $invalidatecachekey);
1144
 
1145
        $invalidate2cachekey = \core_courseformat\base::session_cache($course2);
1146
        $this->assertEquals($course2cachekey, $invalidate2cachekey);
1147
    }
1 efrain 1148
}
1149
 
1150
/**
1151
 * Class format_testformat.
1152
 *
1153
 * A test class that simulates a course format that doesn't define 'news_items' in default blocks.
1154
 *
1155
 * @copyright 2016 Jun Pataleta <jun@moodle.com>
1156
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1157
 */
1158
class format_testformat extends core_courseformat\base {
1159
    /**
1160
     * Returns the list of blocks to be automatically added for the newly created course.
1161
     *
1162
     * @return array
1163
     */
1164
    public function get_default_blocks() {
1165
        return [
1166
            BLOCK_POS_RIGHT => [],
1167
            BLOCK_POS_LEFT => []
1168
        ];
1169
    }
1170
}
1171
 
1172
/**
1173
 * Class format_testformatsections.
1174
 *
1175
 * A test class that simulates a course format with sections.
1176
 *
1177
 * @package   core_courseformat
1178
 * @copyright 2023 ISB Bayern
1179
 * @author    Philipp Memmel
1180
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1181
 */
1182
class format_testformatsections extends core_courseformat\base {
1183
    /**
1441 ariadna 1184
     * @var int|null $forcemaxsections The maximum number of sections.
1185
     */
1186
    public ?int $forcemaxsections = null;
1187
    /**
1 efrain 1188
     * Returns if this course format uses sections.
1189
     *
1190
     * @return true
1191
     */
1192
    public function uses_sections() {
1193
        return true;
1194
    }
1195
 
1196
    public function can_sections_be_removed_from_navigation(): bool {
1197
        return true;
1198
    }
1441 ariadna 1199
 
1200
    public function get_last_section_number(): int {
1201
        if ($this->forcemaxsections !== null) {
1202
            return $this->forcemaxsections;
1203
        }
1204
        return parent::get_last_section_number();
1205
    }
1 efrain 1206
}
1207
 
1208
/**
1209
 * Class format_testlegacy.
1210
 *
1211
 * A test class that simulates old course formats that define 'news_items' in default blocks.
1212
 *
1213
 * @copyright 2016 Jun Pataleta <jun@moodle.com>
1214
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1215
 */
1216
class format_testlegacy extends core_courseformat\base {
1217
    /**
1218
     * Returns the list of blocks to be automatically added for the newly created course.
1219
     *
1220
     * @return array
1221
     */
1222
    public function get_default_blocks() {
1223
        return [
1224
            BLOCK_POS_RIGHT => ['news_items'],
1225
            BLOCK_POS_LEFT => []
1226
        ];
1227
    }
1228
}