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_reportbuilder\local\helpers;
20
 
21
use core_customfield_generator;
22
use core_reportbuilder_generator;
23
use core_reportbuilder_testcase;
24
use core_reportbuilder\local\entities\course;
25
use core_reportbuilder\local\filters\boolean_select;
26
use core_reportbuilder\local\filters\date;
27
use core_reportbuilder\local\filters\select;
28
use core_reportbuilder\local\filters\text;
29
use core_reportbuilder\local\report\column;
30
use core_reportbuilder\local\report\filter;
31
use core_course\reportbuilder\datasource\{categories, courses};
32
 
33
defined('MOODLE_INTERNAL') || die();
34
 
35
global $CFG;
36
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
37
 
38
/**
39
 * Unit tests for custom fields helper
40
 *
41
 * @package     core_reportbuilder
42
 * @covers      \core_reportbuilder\local\helpers\custom_fields
43
 * @copyright   2021 David Matamoros <davidmc@moodle.com>
44
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45
 */
46
class custom_fields_test extends core_reportbuilder_testcase {
47
 
48
    /**
49
     * Generate custom fields, one of each type
50
     *
51
     * @return custom_fields
52
     */
53
    private function generate_customfields(): custom_fields {
54
 
55
        /** @var core_customfield_generator $generator */
56
        $generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
57
        $category = $generator->create_category([
58
            'component' => 'core_course',
59
            'area' => 'course',
60
            'itemid' => 0,
61
            'contextid' => \context_system::instance()->id
62
        ]);
63
 
64
        $generator->create_field(
65
            ['categoryid' => $category->get('id'), 'type' => 'text', 'name' => 'Text', 'shortname' => 'text']);
66
 
67
        $generator->create_field(
68
            ['categoryid' => $category->get('id'), 'type' => 'textarea', 'name' => 'Textarea', 'shortname' => 'textarea']);
69
 
70
        $generator->create_field(
71
            ['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox']);
72
 
73
        $generator->create_field(
74
            ['categoryid' => $category->get('id'), 'type' => 'date', 'name' => 'Date', 'shortname' => 'date']);
75
 
76
        $generator->create_field(
77
            ['categoryid' => $category->get('id'), 'type' => 'select', 'name' => 'Select', 'shortname' => 'select',
78
                'configdata' => ['options' => "Cat\nDog", 'defaultvalue' => 'Cat']]);
79
 
80
        $courseentity = new course();
81
        $coursealias = $courseentity->get_table_alias('course');
82
 
83
        // Create an instance of the customfields helper.
84
        return new custom_fields($coursealias . '.id', $courseentity->get_entity_name(),
85
            'core_course', 'course');
86
    }
87
 
88
    /**
89
     * Test for get_columns
90
     */
91
    public function test_get_columns(): void {
92
        $this->resetAfterTest();
93
 
94
        $customfields = $this->generate_customfields();
95
        $columns = $customfields->get_columns();
96
 
97
        $this->assertCount(5, $columns);
98
        $this->assertContainsOnlyInstancesOf(column::class, $columns);
99
 
100
        // Column titles.
101
        $this->assertEquals(
102
            ['Text', 'Textarea', 'Checkbox', 'Date', 'Select'],
103
            array_map(fn(column $column) => $column->get_title(), $columns)
104
        );
105
 
106
        // Column types.
107
        $this->assertEquals(
108
            [column::TYPE_TEXT, column::TYPE_LONGTEXT, column::TYPE_BOOLEAN, column::TYPE_TIMESTAMP, column::TYPE_TEXT],
109
            array_map(fn(column $column) => $column->get_type(), $columns)
110
        );
111
 
112
        // Column sortable.
113
        $this->assertEquals(
114
            [true, false, true, true, true],
115
            array_map(fn(column $column) => $column->get_is_sortable(), $columns)
116
        );
117
    }
118
 
119
    /**
120
     * Test for add_join
121
     */
122
    public function test_add_join(): void {
123
        $this->resetAfterTest();
124
 
125
        $customfields = $this->generate_customfields();
126
 
127
        // By default, we always join on the customfield data table.
128
        $columns = $customfields->get_columns();
129
        $joins = $columns[0]->get_joins();
130
 
131
        $this->assertCount(1, $joins);
132
        $this->assertStringStartsWith('LEFT JOIN {customfield_data}', $joins[0]);
133
 
134
        // Add additional join.
135
        $customfields->add_join('JOIN {test} t ON t.id = id');
136
 
137
        $columns = $customfields->get_columns();
138
        $joins = $columns[0]->get_joins();
139
 
140
        $this->assertCount(2, $joins);
141
        $this->assertEquals('JOIN {test} t ON t.id = id', $joins[0]);
142
        $this->assertStringStartsWith('LEFT JOIN {customfield_data}', $joins[1]);
143
    }
144
 
145
    /**
146
     * Test for add_joins
147
     */
148
    public function test_add_joins(): void {
149
        $this->resetAfterTest();
150
 
151
        $customfields = $this->generate_customfields();
152
 
153
        // Add additional joins.
154
        $customfields->add_joins(['JOIN {test} t ON t.id = id', 'JOIN {test2} t2 ON t2.id = id']);
155
 
156
        $columns = $customfields->get_columns();
157
        $joins = $columns[0]->get_joins();
158
 
159
        $this->assertCount(3, $joins);
160
        $this->assertEquals('JOIN {test} t ON t.id = id', $joins[0]);
161
        $this->assertEquals('JOIN {test2} t2 ON t2.id = id', $joins[1]);
162
        $this->assertStringStartsWith('LEFT JOIN {customfield_data}', $joins[2]);
163
    }
164
 
165
    /**
166
     * Test for get_filters
167
     */
168
    public function test_get_filters(): void {
169
        $this->resetAfterTest();
170
 
171
        $customfields = $this->generate_customfields();
172
        $filters = $customfields->get_filters();
173
 
174
        $this->assertCount(5, $filters);
175
        $this->assertContainsOnlyInstancesOf(filter::class, $filters);
176
 
177
        // Filter titles.
178
        $this->assertEquals(
179
            ['Text', 'Textarea', 'Checkbox', 'Date', 'Select'],
180
            array_map(fn(filter $filter) => $filter->get_header(), $filters)
181
        );
182
    }
183
 
184
    /**
185
     * Test that adding custom field columns to a report returns expected values
186
     */
187
    public function test_custom_report_content(): void {
188
        $this->resetAfterTest();
189
 
190
        $this->generate_customfields();
191
 
192
        $course = $this->getDataGenerator()->create_course(['customfields' => [
193
            ['shortname' => 'text', 'value' => 'Hello'],
194
            ['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
195
            ['shortname' => 'checkbox', 'value' => true],
196
            ['shortname' => 'date', 'value' => 1669852800],
197
            ['shortname' => 'select', 'value' => 2],
198
        ]]);
199
 
200
        /** @var core_reportbuilder_generator $generator */
201
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
202
        $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
203
 
204
        // Add custom field columns to the report.
205
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
206
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_text']);
207
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_textarea']);
208
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_checkbox']);
209
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_date']);
210
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_select']);
211
 
212
        $content = $this->get_custom_report_content($report->get('id'));
213
 
214
        $this->assertEquals([
215
            $course->fullname,
216
            'Hello',
217
            '<div class="text_to_html">Goodbye</div>',
218
            'Yes',
219
            userdate(1669852800),
220
            'Dog'
221
        ], array_values($content[0]));
222
    }
223
 
224
    /**
225
     * Test that adding custom field columns to report returns expected default values for fields
226
     */
227
    public function test_custom_report_content_column_defaults(): void {
228
        $this->resetAfterTest();
229
 
230
        $this->generate_customfields();
231
 
232
        $category = $this->getDataGenerator()->create_category(['name' => 'Zebras']);
233
        $course = $this->getDataGenerator()->create_course(['category' => $category->id]);
234
 
235
        /** @var core_reportbuilder_generator $generator */
236
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
237
        $report = $generator->create_report(['name' => 'Categories', 'source' => categories::class, 'default' => 0]);
238
 
239
        // Add custom field columns to the report.
240
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:name',
241
            'sortenabled' => 1]);
242
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
243
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_select']);
244
 
245
        $content = $this->get_custom_report_content($report->get('id'));
246
        $this->assertEquals([
247
            ['Category 1', '', ''],
248
            [$category->name, $course->fullname, 'Cat'],
249
        ], array_map('array_values', $content));
250
    }
251
 
252
    /**
253
     * Data provider for {@see test_custom_report_filter}
254
     *
255
     * @return array[]
256
     */
257
    public function custom_report_filter_provider(): array {
258
        return [
259
            'Filter by text custom field' => ['course:customfield_text', [
260
                'course:customfield_text_operator' => text::IS_EQUAL_TO,
261
                'course:customfield_text_value' => 'Hello',
262
            ], true],
263
            'Filter by text custom field (no match)' => ['course:customfield_text', [
264
                'course:customfield_text_operator' => text::IS_EQUAL_TO,
265
                'course:customfield_text_value' => 'Goodbye',
266
            ], false],
267
            'Filter by textarea custom field' => ['course:customfield_textarea', [
268
                'course:customfield_textarea_operator' => text::IS_EQUAL_TO,
269
                'course:customfield_textarea_value' => 'Goodbye',
270
            ], true],
271
            'Filter by textarea custom field (no match)' => ['course:customfield_textarea', [
272
                'course:customfield_textarea_operator' => text::IS_EQUAL_TO,
273
                'course:customfield_textarea_value' => 'Hello',
274
            ], false],
275
            'Filter by checkbox custom field' => ['course:customfield_checkbox', [
276
                'course:customfield_checkbox_operator' => boolean_select::CHECKED,
277
            ], true],
278
            'Filter by checkbox custom field (no match)' => ['course:customfield_checkbox', [
279
                'course:customfield_checkbox_operator' => boolean_select::NOT_CHECKED,
280
            ], false],
281
            'Filter by date custom field' => ['course:customfield_date', [
282
                'course:customfield_date_operator' => date::DATE_RANGE,
283
                'course:customfield_date_from' => 1622502000,
284
            ], true],
285
            'Filter by date custom field (no match)' => ['course:customfield_date', [
286
                'course:customfield_date_operator' => date::DATE_RANGE,
287
                'course:customfield_date_to' => 1622502000,
288
            ], false],
289
            'Filter by select custom field' => ['course:customfield_select', [
290
                'course:customfield_select_operator' => select::EQUAL_TO,
291
                'course:customfield_select_value' => 2,
292
            ], true],
293
            'Filter by select custom field (no match)' => ['course:customfield_select', [
294
                'course:customfield_select_operator' => select::EQUAL_TO,
295
                'course:customfield_select_value' => 1,
296
            ], false],
297
        ];
298
    }
299
 
300
    /**
301
     * Test filtering report by custom fields
302
     *
303
     * @param string $filtername
304
     * @param array $filtervalues
305
     * @param bool $expectmatch
306
     *
307
     * @dataProvider custom_report_filter_provider
308
     */
309
    public function test_custom_report_filter(string $filtername, array $filtervalues, bool $expectmatch): void {
310
        $this->resetAfterTest();
311
 
312
        $this->generate_customfields();
313
 
314
        $course = $this->getDataGenerator()->create_course(['customfields' => [
315
            ['shortname' => 'text', 'value' => 'Hello'],
316
            ['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
317
            ['shortname' => 'checkbox', 'value' => true],
318
            ['shortname' => 'date', 'value' => 1669852800],
319
            ['shortname' => 'select', 'value' => 2],
320
        ]]);
321
 
322
        /** @var core_reportbuilder_generator $generator */
323
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
324
 
325
        // Create report containing single column, and given filter.
326
        $report = $generator->create_report(['name' => 'Users', 'source' => courses::class, 'default' => 0]);
327
        $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
328
 
329
        // Add filter, set it's values.
330
        $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
331
        $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
332
 
333
        if ($expectmatch) {
334
            $this->assertCount(1, $content);
335
            $this->assertEquals($course->fullname, reset($content[0]));
336
        } else {
337
            $this->assertEmpty($content);
338
        }
339
    }
340
 
341
    /**
342
     * Stress test course datasource using custom fields
343
     *
344
     * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
345
     */
346
    public function test_stress_datasource(): void {
347
        if (!PHPUNIT_LONGTEST) {
348
            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
349
        }
350
 
351
        $this->resetAfterTest();
352
 
353
        $this->generate_customfields();
354
        $course = $this->getDataGenerator()->create_course(['customfields' => [
355
            ['shortname' => 'text', 'value' => 'Hello'],
356
            ['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
357
            ['shortname' => 'checkbox', 'value' => true],
358
            ['shortname' => 'date', 'value' => 1669852800],
359
            ['shortname' => 'select', 'value' => 2],
360
        ]]);
361
 
362
        $this->datasource_stress_test_columns(courses::class);
363
        $this->datasource_stress_test_columns_aggregation(courses::class);
364
        $this->datasource_stress_test_conditions(courses::class, 'course:idnumber');
365
    }
366
}
367