Proyectos de Subversion Moodle

Rev

| 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
declare(strict_types=1);
18
 
19
namespace core_course\reportbuilder\datasource;
20
 
21
use context_course;
22
use core_reportbuilder_testcase;
23
use core_reportbuilder_generator;
24
use core_reportbuilder\local\filters\boolean_select;
25
use core_reportbuilder\local\filters\date;
26
use core_reportbuilder\local\filters\select;
27
use core_reportbuilder\local\filters\tags;
28
use core_reportbuilder\local\filters\text;
29
 
30
defined('MOODLE_INTERNAL') || die();
31
 
32
global $CFG;
33
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
34
 
35
/**
36
 * Unit tests for courses datasources
37
 *
38
 * @package     core_course
39
 * @covers      \core_course\reportbuilder\datasource\courses
40
 * @copyright   2021 Paul Holden <paulh@moodle.com>
41
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42
 */
43
class courses_test extends core_reportbuilder_testcase {
44
 
45
    /**
46
     * Test default datasource
47
     */
48
    public function test_datasource_default(): void {
49
        $this->resetAfterTest();
50
 
51
        // Test subject.
52
        $category = $this->getDataGenerator()->create_category(['name' => 'My cats']);
53
        $courseone = $this->getDataGenerator()->create_course([
54
            'category' => $category->id,
55
            'fullname' => 'Feline fine',
56
            'shortname' => 'C102',
57
            'idnumber' => 'CAT102'
58
        ]);
59
        $coursetwo = $this->getDataGenerator()->create_course([
60
            'category' => $category->id,
61
            'fullname' => 'All about cats',
62
            'shortname' => 'C101',
63
            'idnumber' => 'CAT101'
64
        ]);
65
 
66
        /** @var core_reportbuilder_generator $generator */
67
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
68
        $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 1]);
69
 
70
        $content = $this->get_custom_report_content($report->get('id'));
71
 
72
        // Default columns are category, shortname, fullname, idnumber. Sorted by category, shortname, fullname.
73
        $this->assertEquals([
74
            [$category->name, $coursetwo->shortname, $coursetwo->fullname, $coursetwo->idnumber],
75
            [$category->name, $courseone->shortname, $courseone->fullname, $courseone->idnumber],
76
        ], array_map('array_values', $content));
77
    }
78
 
79
    /**
80
     * Test datasource columns that aren't added by default
81
     */
82
    public function test_datasource_non_default_columns(): void {
83
        $this->resetAfterTest();
84
 
85
        $category = $this->getDataGenerator()->create_category([
86
            'name' => 'Animals',
87
            'idnumber' => 'CAT101',
88
            'description' => 'Category description',
89
        ]);
90
        $course = $this->getDataGenerator()->create_course([
91
            'category' => $category->id,
92
            'fullname' => 'Cats',
93
            'summary' => 'Course description',
94
            'theme' => 'boost',
95
            'tags' => ['Horses'],
96
        ]);
97
 
98
        // Add a course image.
99
        get_file_storage()->create_file_from_string([
100
            'contextid' => context_course::instance($course->id)->id,
101
            'component' => 'course',
102
            'filearea' => 'overviewfiles',
103
            'itemid' => 0,
104
            'filepath' => '/',
105
            'filename' => 'HelloWorld.jpg',
106
        ], 'HelloWorld');
107
 
108
        /** @var core_reportbuilder_generator $generator */
109
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
110
        $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
111
 
112
        // Course.
113
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']);
114
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseshortnamewithlink']);
115
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseidnumberewithlink']);
116
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:summary']);
117
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:format']);
118
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:startdate']);
119
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enddate']);
120
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:visible']);
121
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmode']);
122
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmodeforce']);
123
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:lang']);
124
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:calendartype']);
125
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:theme']);
126
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enablecompletion']);
127
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:downloadcontent']);
128
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:timecreated']);
129
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:timemodified']);
130
 
131
        // Tags.
132
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:name']);
133
 
134
        // File entity.
135
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:name']);
136
 
137
        $content = $this->get_custom_report_content($report->get('id'));
138
        $this->assertCount(1, $content);
139
 
140
        [
141
            $coursenamewithlink,
142
            $courseshortnamewithlink,
143
            $courseidnumberwithlink,
144
            $coursesummary,
145
            $courseformat,
146
            $coursestartdate,
147
            $courseenddate,
148
            $coursevisible,
149
            $coursegroupmode,
150
            $coursegroupmodeforce,
151
            $courselang,
152
            $coursecalendar,
153
            $coursetheme,
154
            $coursecompletion,
155
            $coursedownload,
156
            $coursetimecreated,
157
            $coursetimemodified,
158
            $tagname,
159
            $filename,
160
        ] = array_values($content[0]);
161
 
162
        // Course.
163
        $this->assertStringContainsString($course->fullname, $coursenamewithlink);
164
        $this->assertStringContainsString($course->shortname, $courseshortnamewithlink);
165
        $this->assertStringContainsString($course->idnumber, $courseidnumberwithlink);
166
        $this->assertEquals(format_text($course->summary, $course->summaryformat), $coursesummary);
167
        $this->assertEquals('Custom sections', $courseformat);
168
        $this->assertEquals(userdate($course->startdate), $coursestartdate);
169
        $this->assertEmpty($courseenddate);
170
        $this->assertEquals('Yes', $coursevisible);
171
        $this->assertEquals('No groups', $coursegroupmode);
172
        $this->assertEquals('No', $coursegroupmodeforce);
173
        $this->assertEmpty($courselang);
174
        $this->assertEmpty($coursecalendar);
175
        $this->assertEquals('Boost', $coursetheme);
176
        $this->assertEquals('No', $coursecompletion);
177
        $this->assertEmpty($coursedownload);
178
        $this->assertEquals(userdate($course->timecreated), $coursetimecreated);
179
        $this->assertEquals(userdate($course->timemodified), $coursetimemodified);
180
 
181
        // Tags.
182
        $this->assertEquals('Horses', $tagname);
183
 
184
        // File.
185
        $this->assertEquals('HelloWorld.jpg', $filename);
186
    }
187
 
188
    /**
189
     * Tests courses datasource using multilang filters
190
     */
191
    public function test_courses_datasource_multilang_filters(): void {
192
        $this->resetAfterTest();
193
 
194
        filter_set_global_state('multilang', TEXTFILTER_ON);
195
        filter_set_applies_to_strings('multilang', true);
196
 
197
        // Test subject.
198
        $category = $this->getDataGenerator()->create_category([
199
            'name' => '<span class="multilang" lang="en">Cat (en)</span><span class="multilang" lang="es">Cat (es)</span>',
200
        ]);
201
        $course = $this->getDataGenerator()->create_course([
202
            'category' => $category->id,
203
            'fullname' => '<span class="multilang" lang="en">Crs (en)</span><span class="multilang" lang="es">Crs (es)</span>',
204
        ]);
205
 
206
        /** @var core_reportbuilder_generator $generator */
207
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
208
 
209
        // Create a report containing columns that support multilang content.
210
        $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
211
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:name']);
212
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
213
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']);
214
 
215
        $content = $this->get_custom_report_content($report->get('id'));
216
        $this->assertCount(1, $content);
217
 
218
        $contentrow = array_values(reset($content));
219
        $this->assertEquals([
220
            'Cat (en)',
221
            'Crs (en)',
222
            '<a href="' . (string) course_get_url($course->id) . '">Crs (en)</a>',
223
        ], $contentrow);
224
    }
225
 
226
    /**
227
     * Data provider for {@see test_datasource_filters}
228
     *
229
     * @return array[]
230
     */
231
    public function datasource_filters_provider(): array {
232
        return [
233
            // Category.
234
            'Filter category name' => ['course_category:text', [
235
                'course_category:text_operator' => text::IS_EQUAL_TO,
236
                'course_category:text_value' => 'Animals',
237
            ], true],
238
            'Filter category name (no match)' => ['course_category:text', [
239
                'course_category:text_operator' => text::IS_EQUAL_TO,
240
                'course_category:text_value' => 'Fruit',
241
            ], false],
242
 
243
            // Course.
244
            'Filter course' => ['course:courseselector', [
245
                'course:courseselector_values' => [-1],
246
            ], false],
247
            'Filter course fullname' => ['course:fullname', [
248
                'course:fullname_operator' => text::IS_EQUAL_TO,
249
                'course:fullname_value' => 'Equine',
250
            ], true],
251
            'Filter course fullname (no match)' => ['course:fullname', [
252
                'course:fullname_operator' => text::IS_EQUAL_TO,
253
                'course:fullname_value' => 'Foxes',
254
            ], false],
255
            'Filter course shortname' => ['course:shortname', [
256
                'course:shortname_operator' => text::IS_EQUAL_TO,
257
                'course:shortname_value' => 'EQ101',
258
            ], true],
259
            'Filter course shortname (no match)' => ['course:shortname', [
260
                'course:shortname_operator' => text::IS_EQUAL_TO,
261
                'course:shortname_value' => 'FX101',
262
            ], false],
263
            'Filter course idnumber' => ['course:idnumber', [
264
                'course:idnumber_operator' => text::IS_EQUAL_TO,
265
                'course:idnumber_value' => 'E-101AB',
266
            ], true],
267
            'Filter course idnumber (no match)' => ['course:idnumber', [
268
                'course:idnumber_operator' => text::IS_EQUAL_TO,
269
                'course:idnumber_value' => 'F-101XT',
270
            ], false],
271
            'Filter course summary' => ['course:summary', [
272
                'course:summary_operator' => text::CONTAINS,
273
                'course:summary_value' => 'Lorem ipsum',
274
            ], true],
275
            'Filter course summary (no match)' => ['course:summary', [
276
                'course:summary_operator' => text::IS_EQUAL_TO,
277
                'course:summary_value' => 'Fiat',
278
            ], false],
279
            'Filter course format' => ['course:format', [
280
                'course:format_operator' => select::EQUAL_TO,
281
                'course:format_value' => 'topics',
282
            ], true],
283
            'Filter course format (no match)' => ['course:format', [
284
                'course:format_operator' => select::EQUAL_TO,
285
                'course:format_value' => 'weekly',
286
            ], false],
287
            'Filter course startdate' => ['course:startdate', [
288
                'course:startdate_operator' => date::DATE_RANGE,
289
                'course:startdate_from' => 1622502000,
290
            ], true],
291
            'Filter course startdate (no match)' => ['course:startdate', [
292
                'course:startdate_operator' => date::DATE_RANGE,
293
                'course:startdate_to' => 1622502000,
294
            ], false],
295
            'Filter course enddate' => ['course:enddate', [
296
                'course:enddate_operator' => date::DATE_EMPTY,
297
            ], true],
298
            'Filter course enddate (no match)' => ['course:enddate', [
299
                'course:enddate_operator' => date::DATE_NOT_EMPTY,
300
            ], false],
301
            'Filter course visible' => ['course:visible', [
302
                'course:visible_operator' => boolean_select::CHECKED,
303
            ], true],
304
            'Filter course visible (no match)' => ['course:visible', [
305
                'course:visible_operator' => boolean_select::NOT_CHECKED,
306
            ], false],
307
            'Filter course groupmode' => ['course:groupmode', [
308
                'course:groupmode_operator' => select::EQUAL_TO,
309
                'course:groupmode_value' => 0, // No groups.
310
            ], true],
311
            'Filter course groupmode (no match)' => ['course:groupmode', [
312
                'course:groupmode_operator' => select::EQUAL_TO,
313
                'course:groupmode_value' => 1, // Separate groups.
314
            ], false],
315
            'Filter course groupmodeforce' => ['course:groupmodeforce', [
316
                'course:groupmodeforce_operator' => boolean_select::NOT_CHECKED,
317
            ], true],
318
            'Filter course groupmodeforce (no match)' => ['course:groupmodeforce', [
319
                'course:groupmodeforce_operator' => boolean_select::CHECKED,
320
            ], false],
321
            'Filter course lang' => ['course:lang', [
322
                'course:lang_operator' => select::EQUAL_TO,
323
                'course:lang_value' => 'en',
324
            ], true],
325
            'Filter course lang (no match)' => ['course:lang', [
326
                'course:lang_operator' => select::EQUAL_TO,
327
                'course:lang_value' => 'de',
328
            ], false],
329
            'Filter course calendartype' => ['course:calendartype', [
330
                'course:calendartype_operator' => select::EQUAL_TO,
331
                'course:calendartype_value' => 'gregorian',
332
            ], true],
333
            'Filter course calendartype (no match)' => ['course:calendartype', [
334
                'course:calendartype_operator' => select::EQUAL_TO,
335
                'course:calendartype_value' => 'hijri',
336
            ], false],
337
            'Filter course theme' => ['course:theme', [
338
                'course:theme_operator' => select::EQUAL_TO,
339
                'course:theme_value' => 'boost',
340
            ], true],
341
            'Filter course theme (no match)' => ['course:theme', [
342
                'course:theme_operator' => select::EQUAL_TO,
343
                'course:theme_value' => 'classic',
344
            ], false],
345
            'Filter course enablecompletion' => ['course:enablecompletion', [
346
                'course:enablecompletion_operator' => boolean_select::NOT_CHECKED,
347
            ], true],
348
            'Filter course enablecompletion (no match)' => ['course:enablecompletion', [
349
                'course:enablecompletion_operator' => boolean_select::CHECKED,
350
            ], false],
351
            'Filter course downloadcontent' => ['course:downloadcontent', [
352
                'course:downloadcontent_operator' => boolean_select::CHECKED,
353
            ], true],
354
            'Filter course downloadcontent (no match)' => ['course:downloadcontent', [
355
                'course:downloadcontent_operator' => boolean_select::NOT_CHECKED,
356
            ], false],
357
            'Filter course timecreated' => ['course:timecreated', [
358
                'course:timecreated_operator' => date::DATE_RANGE,
359
                'course:timecreated_from' => 1622502000,
360
            ], true],
361
            'Filter course timecreated (no match)' => ['course:timecreated', [
362
                'course:timecreated_operator' => date::DATE_RANGE,
363
                'course:timecreated_to' => 1622502000,
364
            ], false],
365
            'Filter course timemodified' => ['course:timemodified', [
366
                'course:timemodified_operator' => date::DATE_RANGE,
367
                'course:timemodified_from' => 1622502000,
368
            ], true],
369
            'Filter course timemodified (no match)' => ['course:timemodified', [
370
                'course:timemodified_operator' => date::DATE_RANGE,
371
                'course:timemodified_to' => 1622502000,
372
            ], false],
373
 
374
            // Tags.
375
            'Filter tag name' => ['tag:name', [
376
                'tag:name_operator' => tags::EQUAL_TO,
377
                'tag:name_value' => [-1],
378
            ], false],
379
            'Filter tag name not empty' => ['tag:name', [
380
                'tag:name_operator' => tags::NOT_EMPTY,
381
            ], true],
382
 
383
            // File.
384
            'Filter file name empty' => ['file:name', [
385
                'file:name_operator' => text::IS_EMPTY,
386
            ], true],
387
        ];
388
    }
389
 
390
    /**
391
     * Test datasource filters
392
     *
393
     * @param string $filtername
394
     * @param array $filtervalues
395
     * @param bool $expectmatch
396
     *
397
     * @dataProvider datasource_filters_provider
398
     */
399
    public function test_datasource_filters(string $filtername, array $filtervalues, bool $expectmatch): void {
400
        $this->resetAfterTest();
401
 
402
        $category = $this->getDataGenerator()->create_category(['name' => 'Animals']);
403
        $course = $this->getDataGenerator()->create_course([
404
            'category' => $category->id,
405
            'fullname' => 'Equine',
406
            'shortname' => 'EQ101',
407
            'idnumber' => 'E-101AB',
408
            'lang' => 'en',
409
            'calendartype' => 'gregorian',
410
            'theme' => 'boost',
411
            'downloadcontent' => 1,
412
            'tags' => ['Horses'],
413
        ]);
414
 
415
        /** @var core_reportbuilder_generator $generator */
416
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
417
 
418
        // Create report containing single column, and given filter.
419
        $report = $generator->create_report(['name' => 'Tasks', 'source' => courses::class, 'default' => 0]);
420
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
421
 
422
        // Add filter, set it's values.
423
        $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
424
        $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
425
 
426
        if ($expectmatch) {
427
            $this->assertCount(1, $content);
428
            $this->assertEquals($course->fullname, reset($content[0]));
429
        } else {
430
            $this->assertEmpty($content);
431
        }
432
    }
433
 
434
    /**
435
     * Stress test datasource
436
     *
437
     * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
438
     */
439
    public function test_stress_datasource(): void {
440
        if (!PHPUNIT_LONGTEST) {
441
            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
442
        }
443
 
444
        $this->resetAfterTest();
445
 
446
        $category = $this->getDataGenerator()->create_category();
447
        $course = $this->getDataGenerator()->create_course(['category' => $category->id]);
448
 
449
        $this->datasource_stress_test_columns(courses::class);
450
        $this->datasource_stress_test_columns_aggregation(courses::class);
451
        $this->datasource_stress_test_conditions(courses::class, 'course:idnumber');
452
    }
453
}