Proyectos de Subversion Moodle

Rev

Rev 11 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 11 Rev 1441
Línea 14... Línea 14...
14
// You should have received a copy of the GNU General Public License
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/>.
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
Línea 16... Línea 16...
16
 
16
 
Línea 17... Línea 17...
17
namespace qbank_managecategories;
17
namespace qbank_managecategories;
-
 
18
 
Línea 18... Línea -...
18
 
-
 
19
defined('MOODLE_INTERNAL') || die();
19
use core\exception\moodle_exception;
Línea 20... Línea 20...
20
 
20
use core_question\category_manager;
-
 
21
 
21
use moodle_url;
22
defined('MOODLE_INTERNAL') || die;
Línea 22... Línea 23...
22
use core_question\local\bank\question_edit_contexts;
23
 
23
 
24
global $CFG;
24
global $CFG;
25
require_once($CFG->dirroot . '/question/bank/managecategories/tests/manage_category_test_base.php');
Línea 31... Línea 32...
31
 * @copyright  2006 The Open University
32
 * @copyright  2006 The Open University
32
 * @author     2021, Guillermo Gomez Arias <guillermogomez@catalyst-au.net>
33
 * @author     2021, Guillermo Gomez Arias <guillermogomez@catalyst-au.net>
33
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 * @coversDefaultClass \qbank_managecategories\helper
35
 * @coversDefaultClass \qbank_managecategories\helper
35
 */
36
 */
36
class helper_test extends \advanced_testcase {
37
final class helper_test extends manage_category_test_base {
37
 
-
 
38
    use \quiz_question_helper_test_trait;
38
    use \quiz_question_helper_test_trait;
Línea 39... Línea 39...
39
 
39
 
40
    /**
40
    /**
41
     * @var \context_module module context.
41
     * @var \context_module module context.
Línea 56... Línea 56...
56
     * @var \stdClass quiz object.
56
     * @var \stdClass quiz object.
57
     */
57
     */
58
    protected $quiz;
58
    protected $quiz;
Línea 59... Línea 59...
59
 
59
 
60
    /**
-
 
61
     * @var question_category_object used in the tests.
-
 
62
     */
-
 
63
    protected $qcobject;
-
 
64
 
-
 
65
    /**
60
    /**
66
     * Tests initial setup.
61
     * Tests initial setup.
67
     */
62
     */
68
    protected function setUp(): void {
63
    protected function setUp(): void {
69
        parent::setUp();
64
        parent::setUp();
70
        self::setAdminUser();
65
        self::setAdminUser();
Línea 71... Línea 66...
71
        $this->resetAfterTest();
66
        $this->resetAfterTest();
72
 
67
 
73
        $datagenerator = $this->getDataGenerator();
68
        $datagenerator = $this->getDataGenerator();
-
 
69
        $this->course = $datagenerator->create_course();
74
        $this->course = $datagenerator->create_course();
70
        $this->quiz = $datagenerator->create_module(
-
 
71
            'quiz',
75
        $this->quiz = $datagenerator->create_module('quiz',
72
            ['course' => $this->course->id, 'name' => 'Quiz 1'],
76
                ['course' => $this->course->id, 'name' => 'Quiz 1']);
73
        );
77
        $this->qgenerator = $datagenerator->get_plugin_generator('core_question');
-
 
78
        $this->context = \context_module::instance($this->quiz->cmid);
-
 
79
 
-
 
80
        $contexts = new question_edit_contexts($this->context);
-
 
81
        $this->qcobject = new question_category_object(null,
-
 
82
            new moodle_url('/question/bank/managecategories/category.php', ['courseid' => SITEID]),
-
 
83
            $contexts->having_one_edit_tab_cap('categories'), 0, null, 0,
74
        $this->qgenerator = $datagenerator->get_plugin_generator('core_question');
Línea 84... Línea 75...
84
            $contexts->having_cap('moodle/question:add'));
75
        $this->context = \context_module::instance($this->quiz->cmid);
85
    }
76
    }
86
 
77
 
87
    /**
78
    /**
88
     * Test question_remove_stale_questions_from_category function.
79
     * Test question_remove_stale_questions_from_category function.
89
     *
80
     *
90
     * @covers ::question_remove_stale_questions_from_category
81
     * @covers ::question_remove_stale_questions_from_category
Línea -... Línea 82...
-
 
82
     */
-
 
83
    public function test_question_remove_stale_questions_from_category(): void {
-
 
84
        global $DB;
-
 
85
 
-
 
86
        $this->setAdminUser();
-
 
87
        $this->resetAfterTest();
-
 
88
 
91
     */
89
        // Quiz and its context.
92
    public function test_question_remove_stale_questions_from_category(): void {
90
        $quiz = $this->create_quiz();
93
        global $DB;
91
 
Línea -... Línea 92...
-
 
92
        // Create category 1 and one question.
94
 
93
        $qcat1 = $this->create_question_category_for_a_quiz($quiz);
95
        $qcat1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
94
        $q1a = $this->create_question_in_a_category('shortanswer', $qcat1->id);
96
        $q1a = $this->qgenerator->create_question('shortanswer', null, ['category' => $qcat1->id]);     // Will be hidden.
95
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q1a->id]);
97
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q1a->id]);
96
 
98
 
97
        // Create category 2 and two questions.
-
 
98
        $qcat2 = $this->create_question_category_for_a_quiz($quiz);
-
 
99
        $q2a = $this->create_question_in_a_category('shortanswer', $qcat2->id);
99
        $qcat2 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
100
        $q2b = $this->create_question_in_a_category('shortanswer', $qcat2->id);
Línea 100... Línea 101...
100
        $q2a = $this->qgenerator->create_question('shortanswer', null, ['category' => $qcat2->id]);     // Will be hidden.
101
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q2a->id]);
101
        $q2b = $this->qgenerator->create_question('shortanswer', null, ['category' => $qcat2->id]);     // Will be hidden but used.
102
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q2b->id]);
Línea 102... Línea 103...
102
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q2a->id]);
103
 
103
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q2b->id]);
104
        // Add question to the quiz.
-
 
105
        quiz_add_quiz_question($q2b->id, $quiz);
104
        quiz_add_quiz_question($q2b->id, $this->quiz);
106
 
105
 
107
        // Adding a new random question does not add a new question, adds a question_set_references record.
106
        // Adding a new random question does not add a new question, adds a question_set_references record.
108
        $this->add_random_questions($quiz->id, 0, $qcat2->id, 1);
107
        $this->add_random_questions($this->quiz->id, 0, $qcat2->id, 1);
109
 
108
 
110
        // We added one random question to the quiz and we expect the quiz to have only one random question.
109
        // We added one random question to the quiz and we expect the quiz to have only one random question.
111
        $q2d = $DB->get_record_sql(
-
 
112
            "SELECT qsr.*
-
 
113
               FROM {quiz_slots} qs
Línea 110... Línea 114...
110
        $q2d = $DB->get_record_sql("SELECT qsr.*
114
               JOIN {question_set_references} qsr ON qsr.itemid = qs.id
111
                                      FROM {quiz_slots} qs
115
              WHERE qs.quizid = ?
112
                                      JOIN {question_set_references} qsr ON qsr.itemid = qs.id
116
                AND qsr.component = ?
113
                                     WHERE qs.quizid = ?
117
                AND qsr.questionarea = ?",
Línea -... Línea 118...
-
 
118
            [$quiz->id, 'mod_quiz', 'slot'],
-
 
119
            MUST_EXIST
114
                                       AND qsr.component = ?
120
        );
115
                                       AND qsr.questionarea = ?",
121
 
Línea 116... Línea 122...
116
            [$this->quiz->id, 'mod_quiz', 'slot'], MUST_EXIST);
122
        // The following 2 lines have to be after the quiz_add_random_questions() call above.
117
 
123
        // Otherwise, quiz_add_random_questions() will to be "smart" and use them instead of creating a new "random" question.
118
        // The following 2 lines have to be after the quiz_add_random_questions() call above.
124
        $q1b = $this->create_question_in_a_category('random', $qcat1->id);
119
        // Otherwise, quiz_add_random_questions() will to be "smart" and use them instead of creating a new "random" question.
125
        $q2c = $this->create_question_in_a_category('random', $qcat2->id);
Línea 120... Línea 126...
120
        $q1b = $this->qgenerator->create_question('random', null, ['category' => $qcat1->id]);          // Will not be used.
126
 
121
        $q2c = $this->qgenerator->create_question('random', null, ['category' => $qcat2->id]);          // Will not be used.
127
        $contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
122
 
128
        $manager = new category_manager();
123
        $this->assertEquals(2, count($this->qcobject->get_real_question_ids_in_category($qcat1->id)));
129
        $this->assertEquals(2, count($manager->get_real_question_ids_in_category($qcat1->id, $contexts)));
124
        $this->assertEquals(3, count($this->qcobject->get_real_question_ids_in_category($qcat2->id)));
130
        $this->assertEquals(3, count($manager->get_real_question_ids_in_category($qcat2->id, $contexts)));
125
 
131
 
Línea 126... Línea 132...
126
        // Non-existing category, nothing will happen.
132
        // Non-existing category, nothing will happen.
127
        helper::question_remove_stale_questions_from_category(0);
133
        helper::question_remove_stale_questions_from_category(0);
128
        $this->assertEquals(2, count($this->qcobject->get_real_question_ids_in_category($qcat1->id)));
134
        $this->assertEquals(2, count($manager->get_real_question_ids_in_category($qcat1->id, $contexts)));
129
        $this->assertEquals(3, count($this->qcobject->get_real_question_ids_in_category($qcat2->id)));
135
        $this->assertEquals(3, count($manager->get_real_question_ids_in_category($qcat2->id, $contexts)));
130
 
136
 
131
        // First category, should be empty afterwards.
137
        // First category, should be empty afterwards.
132
        helper::question_remove_stale_questions_from_category($qcat1->id);
138
        helper::question_remove_stale_questions_from_category($qcat1->id);
133
        $this->assertEquals(0, count($this->qcobject->get_real_question_ids_in_category($qcat1->id)));
139
        $this->assertEquals(0, count($manager->get_real_question_ids_in_category($qcat1->id, $contexts)));
-
 
140
        $this->assertEquals(3, count($manager->get_real_question_ids_in_category($qcat2->id, $contexts)));
134
        $this->assertEquals(3, count($this->qcobject->get_real_question_ids_in_category($qcat2->id)));
141
        $this->assertFalse($DB->record_exists('question', ['id' => $q1a->id]));
-
 
142
        $this->assertFalse($DB->record_exists('question', ['id' => $q1b->id]));
135
        $this->assertFalse($DB->record_exists('question', ['id' => $q1a->id]));
143
 
Línea -... Línea 144...
-
 
144
        // Second category, used questions should be left untouched.
136
        $this->assertFalse($DB->record_exists('question', ['id' => $q1b->id]));
145
        helper::question_remove_stale_questions_from_category($qcat2->id);
137
 
146
        $this->assertEquals(0, count($manager->get_real_question_ids_in_category($qcat1->id, $contexts)));
138
        // Second category, used questions should be left untouched.
147
        $this->assertEquals(1, count($manager->get_real_question_ids_in_category($qcat2->id, $contexts)));
139
        helper::question_remove_stale_questions_from_category($qcat2->id);
148
        $this->assertFalse($DB->record_exists('question', ['id' => $q2a->id]));
140
        $this->assertEquals(0, count($this->qcobject->get_real_question_ids_in_category($qcat1->id)));
149
        $this->assertTrue($DB->record_exists('question', ['id' => $q2b->id]));
Línea 155... Línea 164...
155
    public function test_question_can_delete_cat_top_category(): void {
164
    public function test_question_can_delete_cat_top_category(): void {
Línea 156... Línea 165...
156
 
165
 
Línea 157... Línea 166...
157
        $qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
166
        $qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
158
 
167
 
-
 
168
        // Try to delete a top category.
-
 
169
        $categorytop = question_get_top_category($qcategory1->contextid, true)->id;
159
        // Try to delete a top category.
170
        try {
160
        $categorytop = question_get_top_category($qcategory1->id, true)->id;
171
            helper::question_can_delete_cat($categorytop);
-
 
172
        } catch (moodle_exception $e) {
-
 
173
            $this->assertEquals(get_string('cannotdeletetopcat', 'question'), $e->getMessage());
-
 
174
        }
-
 
175
        $this->assertDebuggingCalled(
161
        $this->expectException('moodle_exception');
176
            'Deprecation: qbank_managecategories\helper::question_can_delete_cat has been deprecated since 4.5. ' .
-
 
177
                'Moved to core namespace. ' .
-
 
178
                'Use core_question\category_manager::can_delete_category instead. ' .
162
        $this->expectExceptionMessage(get_string('cannotdeletetopcat', 'question'));
179
                'See MDL-72397 for more information.',
Línea 163... Línea 180...
163
        helper::question_can_delete_cat($categorytop);
180
        );
164
    }
181
    }
165
 
182
 
Línea 172... Línea 189...
172
    public function test_question_can_delete_cat_child_category(): void {
189
    public function test_question_can_delete_cat_child_category(): void {
Línea 173... Línea 190...
173
 
190
 
Línea 174... Línea 191...
174
        $qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
191
        $qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
-
 
192
 
-
 
193
        // Try to delete an only child of top category having also at least one child.
175
 
194
        try {
176
        // Try to delete an only child of top category having also at least one child.
195
            helper::question_can_delete_cat($qcategory1->id);
-
 
196
        } catch (moodle_exception $e) {
-
 
197
            $this->assertEquals(get_string('cannotdeletecate', 'question'), $e->getMessage());
-
 
198
        }
-
 
199
        $this->assertDebuggingCalled(
177
        $this->expectException('moodle_exception');
200
            'Deprecation: qbank_managecategories\helper::question_can_delete_cat has been deprecated since 4.5. ' .
-
 
201
                'Moved to core namespace. ' .
-
 
202
                'Use core_question\category_manager::can_delete_category instead. ' .
178
        $this->expectExceptionMessage(get_string('cannotdeletecate', 'question'));
203
                'See MDL-72397 for more information.',
Línea 179... Línea 204...
179
        helper::question_can_delete_cat($qcategory1->id);
204
        );
180
    }
205
    }
181
 
206
 
Línea 194... Línea 219...
194
 
219
 
195
        // Try to delete a category with and user without the capability.
220
        // Try to delete a category with and user without the capability.
196
        $user = $this->getDataGenerator()->create_user();
221
        $user = $this->getDataGenerator()->create_user();
Línea -... Línea 222...
-
 
222
        $this->setUser($user);
-
 
223
 
197
        $this->setUser($user);
224
        try {
-
 
225
            helper::question_can_delete_cat($qcategory2->id);
198
 
226
        } catch (\required_capability_exception $e) {
-
 
227
            $this->assertEquals(
-
 
228
                get_string('nopermissions', 'error', get_string('question:managecategory', 'role')),
-
 
229
                $e->getMessage(),
-
 
230
            );
-
 
231
        }
199
        $this->expectException(\required_capability_exception::class);
232
        $message = 'Deprecation: qbank_managecategories\helper::question_can_delete_cat has been deprecated since 4.5. ' .
-
 
233
            'Moved to core namespace. ' .
-
 
234
            'Use core_question\category_manager::can_delete_category instead. ' .
200
        $this->expectExceptionMessage(get_string('nopermissions', 'error', get_string('question:managecategory', 'role')));
235
            'See MDL-72397 for more information.';
Línea 201... Línea 236...
201
        helper::question_can_delete_cat($qcategory2->id);
236
        $this->assertdebuggingcalledcount(2, [$message, $message]);
202
    }
237
    }
203
 
238
 
204
    /**
239
    /**
205
     * Test question_category_select_menu function.
240
     * Test question_category_select_menu function.
206
     *
241
     *
207
     * @covers ::question_category_select_menu
242
     * @covers ::question_category_select_menu
-
 
243
     * @covers ::question_category_options
-
 
244
     */
Línea -... Línea 245...
-
 
245
    public function test_question_category_select_menu(): void {
-
 
246
        $this->setAdminUser();
208
     * @covers ::question_category_options
247
        $this->resetAfterTest();
209
     */
248
 
Línea 210... Línea 249...
210
    public function test_question_category_select_menu(): void {
249
        // Create category.
211
 
250
        $quiz = $this->create_quiz();
212
        $this->qgenerator->create_question_category(['contextid' => $this->context->id, 'name' => 'Test this question category']);
251
        $this->create_question_category_for_a_quiz($quiz, ['name' => 'Test this question category']);
Línea 229... Línea 268...
229
     * @covers ::question_fix_top_names
268
     * @covers ::question_fix_top_names
230
     * @covers ::question_add_context_in_key
269
     * @covers ::question_add_context_in_key
231
     * @covers ::add_indented_names
270
     * @covers ::add_indented_names
232
     */
271
     */
233
    public function test_question_category_options(): void {
272
    public function test_question_category_options(): void {
-
 
273
        $this->setAdminUser();
-
 
274
        $this->resetAfterTest();
Línea -... Línea 275...
-
 
275
 
-
 
276
        // Create categories.
-
 
277
        $quiz = $this->create_quiz();
234
 
278
        $context = \context_module::instance($quiz->cmid);
235
        $qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
279
        $qcategory1 = question_get_default_category($context->id);
236
        $qcategory2 = $this->qgenerator->create_question_category(['contextid' => $this->context->id, 'parent' => $qcategory1->id]);
280
        $this->create_question_category_for_a_quiz($quiz, ['parent' => $qcategory1->id]);
Línea 237... Línea 281...
237
        $qcategory3 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
281
        $this->create_question_category_for_a_quiz($quiz);
Línea 238... Línea 282...
238
 
282
 
239
        $contexts = new \core_question\local\bank\question_edit_contexts($this->context);
283
        $contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
240
 
284
 
241
        // Validate that we have the array with the categories tree.
285
        // Validate that we have the array with the categories tree.
242
        $categorycontexts = helper::question_category_options($contexts->having_cap('moodle/question:add'));
286
        $categorycontexts = helper::question_category_options($contexts->having_cap('moodle/question:add'));
Línea 243... Línea 287...
243
        // The quiz name 'Quiz 1' is set in setUp function.
287
        // The quiz name 'Quiz 1' is set in setUp function.
244
        $categorycontext = $categorycontexts['Quiz: Quiz 1'];
288
        $categorycontext = $categorycontexts['Quiz: ' . $quiz->name];
245
        $this->assertCount(3, $categorycontext);
289
        $this->assertCount(3, $categorycontext);
246
 
290
 
247
        // Validate that we have the array with the categories tree and that top category is there.
291
        // Validate that we have the array with the categories tree and that top category is there.
248
        $newcategorycontexts = helper::question_category_options($contexts->having_cap('moodle/question:add'), true);
292
        $newcategorycontexts = helper::question_category_options($contexts->having_cap('moodle/question:add'), true);
249
        foreach ($newcategorycontexts as $key => $categorycontext) {
293
        foreach ($newcategorycontexts as $key => $categorycontext) {
250
            $oldcategorycontext = $categorycontexts[$key];
294
            $oldcategorycontext = $categorycontexts[$key];
-
 
295
            $count = count($oldcategorycontext);
-
 
296
            $this->assertCount($count + 1, $categorycontext);
-
 
297
        }
-
 
298
    }
-
 
299
 
-
 
300
    /**
-
 
301
     * Test that question_category_options function does not include the current category.
-
 
302
     *
-
 
303
     * @covers ::question_category_options
-
 
304
     */
-
 
305
    public function test_question_category_options_exclude_current(): void {
-
 
306
        $this->setAdminUser();
-
 
307
        $this->resetAfterTest();
-
 
308
 
-
 
309
        // Create categories.
-
 
310
        $quiz = $this->create_quiz();
-
 
311
        $context = \context_module::instance($quiz->cmid);
-
 
312
        $qcategory1 = question_get_default_category($context->id);
-
 
313
        $qcategory2 = $this->create_question_category_for_a_quiz($quiz, ['parent' => $qcategory1->id]);
-
 
314
        $qcategory3 = $this->create_question_category_for_a_quiz($quiz);
-
 
315
 
-
 
316
        $contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
-
 
317
 
-
 
318
        $categorycontexts = helper::question_category_options($contexts->having_cap('moodle/question:add'));
-
 
319
        // We get all categories without the currentcat parameter.
-
 
320
        $categorycontext = $categorycontexts['Quiz: ' . $quiz->name];
-
 
321
        $this->assertCount(3, $categorycontext);
-
 
322
 
-
 
323
        // The currentcat category is excluded.
-
 
324
        $newcategorycontexts = helper::question_category_options(
-
 
325
            $contexts->having_cap('moodle/question:add'),
-
 
326
            currentcat: $qcategory2->id,
-
 
327
        );
-
 
328
        $newcategorycontext = $newcategorycontexts['Quiz: ' . $quiz->name];
-
 
329
        $this->assertCount(2, $newcategorycontext);
-
 
330
        $this->assertContains($qcategory1->name, $newcategorycontext);
-
 
331
        $this->assertNotContains($qcategory2->name, $newcategorycontext);
-
 
332
        $this->assertContains($qcategory3->name, $newcategorycontext);
-
 
333
    }
-
 
334
 
-
 
335
    /**
-
 
336
     * Test that get_categories_for_contexts function returns the correct question count number.
-
 
337
     *
-
 
338
     * @covers ::get_categories_for_contexts
-
 
339
     */
-
 
340
    public function test_question_category_question_count(): void {
-
 
341
        global $DB;
-
 
342
        // Create quiz.
-
 
343
        $quiz = $this->quiz;
-
 
344
        $context = \context_module::instance($quiz->cmid);
-
 
345
        // Get the question category and create one hidden question.
-
 
346
        $qcat = question_get_default_category($context->id);
-
 
347
        $q1 = $this->create_question_in_a_category('shortanswer', $qcat->id);
-
 
348
        $DB->set_field('question_versions', 'status', 'hidden', ['questionid' => $q1->id]);
-
 
349
 
-
 
350
        $contexts = new \core_question\local\bank\question_edit_contexts($context);
-
 
351
        $contexts = $contexts->having_cap('moodle/question:add');
-
 
352
        foreach ($contexts as $context) {
-
 
353
            $contextslist[] = $context->id;
-
 
354
        }
-
 
355
        $contextslist = join(', ', $contextslist);
-
 
356
        // Verify we have 0 question in category since it is hidden.
-
 
357
        $categorycontexts = helper::get_categories_for_contexts($contextslist);
-
 
358
        $this->assertEquals(0, reset($categorycontexts)->questioncount);
-
 
359
        // Add an extra question.
-
 
360
        $this->create_question_in_a_category('shortanswer', $qcat->id);
251
            $count = count($oldcategorycontext);
361
        $categorycontexts = helper::get_categories_for_contexts($contextslist);