Merge branch 'MDL-42592_master' of https://github.com/markn86/moodle
[moodle.git] / lib / tests / conditionlib_test.php
blobe1a0b1a32e549c0f2489d835a1705f24917426a4
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.
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/>.
17 /**
18 * Tests for conditional activities.
20 * @package core
21 * @category phpunit
22 * @copyright &copy; 2008 The Open University
23 * @author Sam Marshall
24 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->dirroot . '/lib/conditionlib.php');
33 class core_conditionlib_testcase extends advanced_testcase {
35 protected function setUp() {
36 global $CFG;
37 parent::setUp();
39 $this->resetAfterTest();
41 $CFG->enableavailability = 1;
42 $CFG->enablecompletion = 1;
43 $user = $this->getDataGenerator()->create_user();
44 $this->setUser($user);
47 protected function wipe_condition_cache() {
48 cache::make('core', 'gradecondition')->purge();
51 public function test_constructor() {
52 global $DB;
53 $cm = new stdClass;
55 // Test records.
56 $id = $DB->insert_record('course_modules', (object)array(
57 'showavailability'=>1, 'availablefrom'=>17, 'availableuntil'=>398, 'course'=>64));
59 // No ID.
60 try {
61 $test = new condition_info($cm);
62 $this->fail();
63 } catch (coding_exception $e) {
64 // Do nothing.
67 // No other data.
68 $cm->id = $id;
69 $test = new condition_info($cm, CONDITION_MISSING_EVERYTHING);
70 $this->assertEquals(
71 (object)array('id'=>$id, 'showavailability'=>1,
72 'availablefrom'=>17, 'availableuntil'=>398, 'course'=>64,
73 'conditionsgrade'=>array(), 'conditionscompletion'=>array(),
74 'visible' => 1, 'conditionsfield' => array()),
75 $test->get_full_course_module());
77 // Just the course_modules stuff, check it doesn't request that from db.
78 $cm->showavailability = 0;
79 $cm->availablefrom = 2;
80 $cm->availableuntil = 74;
81 $cm->course = 38;
82 $cm->visible = 1;
83 $test = new condition_info($cm, CONDITION_MISSING_EXTRATABLE);
84 $this->assertEquals(
85 (object)array('id'=>$id, 'showavailability'=>0,
86 'availablefrom'=>2, 'availableuntil'=>74, 'course'=>38,
87 'conditionsgrade' => array(), 'conditionscompletion' => array(),
88 'visible' => 1, 'conditionsfield' => array()),
89 $test->get_full_course_module());
91 // Now let's add some actual grade/completion conditions.
92 $DB->insert_record('course_modules_availability', (object)array(
93 'coursemoduleid'=>$id,
94 'sourcecmid'=>42,
95 'requiredcompletion'=>2
96 ));
97 $DB->insert_record('course_modules_availability', (object)array(
98 'coursemoduleid'=>$id,
99 'sourcecmid'=>666,
100 'requiredcompletion'=>1
102 $DB->insert_record('course_modules_availability', (object)array(
103 'coursemoduleid'=>$id,
104 'gradeitemid'=>37,
105 'grademin'=>5.5
108 $cm = (object)array('id'=>$id);
109 $test = new condition_info($cm, CONDITION_MISSING_EVERYTHING);
110 $fullcm = $test->get_full_course_module();
111 $this->assertEquals(array(42=>2, 666=>1), $fullcm->conditionscompletion);
112 $this->assertEquals(array(37=>(object)array('min'=>5.5, 'max'=>null, 'name'=>'!missing')),
113 $fullcm->conditionsgrade);
117 * Same as above test but for course_sections instead of course_modules.
119 public function test_section_constructor() {
120 global $DB, $CFG;
122 // Test records.
123 $id = $DB->insert_record('course_sections', (object)array(
124 'showavailability' => 1, 'availablefrom' => 17,
125 'availableuntil' => 398, 'course' => 64, 'groupingid' => 13));
127 // No ID.
128 $section = new stdClass;
129 try {
130 $test = new condition_info_section($section);
131 $this->fail();
132 } catch (coding_exception $e) {
133 // Do nothing.
136 // No other data.
137 $section->id = $id;
138 $test = new condition_info_section($section, CONDITION_MISSING_EVERYTHING);
139 $this->assertEquals(
140 (object)array('id' => $id, 'showavailability' => 1, 'groupingid' => 13,
141 'availablefrom' => 17, 'availableuntil' => 398, 'course' => 64,
142 'conditionsgrade' => array(), 'conditionscompletion' => array(),
143 'visible' => 1, 'conditionsfield' => array()),
144 $test->get_full_section());
146 // Just the course_sections stuff; check it doesn't request that from db
147 // (by using fake values and ensuring it still has those).
148 $section->showavailability = 0;
149 $section->availablefrom = 2;
150 $section->availableuntil = 74;
151 $section->course = 38;
152 $section->groupingid = 99;
153 $section->visible = 1;
154 $test = new condition_info_section($section, CONDITION_MISSING_EXTRATABLE);
155 $this->assertEquals(
156 (object)array('id' => $id, 'showavailability' => 0, 'groupingid' => 99,
157 'availablefrom' => 2, 'availableuntil' => 74, 'course' => 38,
158 'conditionsgrade' => array(), 'conditionscompletion' => array(),
159 'visible' => 1, 'conditionsfield' => array()),
160 $test->get_full_section());
162 // Now let's add some actual grade/completion conditions.
163 $DB->insert_record('course_sections_availability', (object)array(
164 'coursesectionid' => $id,
165 'sourcecmid' => 42,
166 'requiredcompletion' => 2
168 $DB->insert_record('course_sections_availability', (object)array(
169 'coursesectionid' => $id,
170 'sourcecmid' => 666,
171 'requiredcompletion' => 1
173 $DB->insert_record('course_sections_availability', (object)array(
174 'coursesectionid' => $id,
175 'gradeitemid' => 37,
176 'grademin' => 5.5
179 $section = (object)array('id' => $id);
180 $test = new condition_info_section($section, CONDITION_MISSING_EVERYTHING);
181 $fullsection = $test->get_full_section();
182 $this->assertEquals(array(42 => 2, 666 => 1), $fullsection->conditionscompletion);
183 $this->assertEquals(array(37 => (object)array('min' => 5.5, 'max' => null, 'name' => '!missing')),
184 $fullsection->conditionsgrade);
187 private function make_course() {
188 $category = $this->getDataGenerator()->create_category(array('name' => 'conditionlibtest'));
189 $course = $this->getDataGenerator()->create_course(
190 array('fullname' => 'Condition test',
191 'shortname' => 'CT1',
192 'category' => $category->id,
193 'enablecompletion' => 1));
194 context_course::instance($course->id);
195 return $course->id;
198 private function make_course_module($courseid, $params = array()) {
199 global $DB;
201 $moduleid = $DB->get_field('modules', 'id', array('name'=>'resource'));
203 $rid = $DB->insert_record('resource', (object)array('course'=>$courseid,
204 'name'=>'xxx', 'alltext'=>'', 'popup'=>''));
205 $settings = (object)array(
206 'course'=>$courseid, 'module'=>$moduleid, 'instance'=>$rid);
207 foreach ($params as $name => $value) {
208 $settings->{$name} = $value;
210 $cmid = $DB->insert_record('course_modules', $settings);
211 rebuild_course_cache($courseid, true);
212 return $cmid;
215 private function make_section($courseid, $cmids, $sectionnum = 0, $params = array()) {
216 global $DB;
217 $record = (object)array(
218 'course' => $courseid,
219 'sequence' => implode(',', $cmids),
220 'section' => $sectionnum);
221 foreach ($params as $name => $value) {
222 $record->{$name} = $value;
224 $sectionid = $DB->insert_record('course_sections', $record);
225 foreach ($cmids as $cmid) {
226 $DB->update_record('course_modules', array('section' => $sectionid, 'id' => $cmid));
228 rebuild_course_cache($courseid, true);
229 return $sectionid;
232 private function make_grouping($courseid, $name) {
233 global $CFG;
234 require_once($CFG->dirroot . '/group/lib.php');
235 return groups_create_grouping((object)array('courseid' => $courseid,
236 'name' => $name));
239 private function make_group($courseid, $name, $groupingid = 0) {
240 global $CFG;
241 require_once($CFG->dirroot . '/group/lib.php');
242 $groupid = groups_create_group((object)array('courseid' => $courseid,
243 'name' => $name));
244 if ($groupingid) {
245 groups_assign_grouping($groupingid, $groupid);
247 return $groupid;
250 public function test_modinfo() {
251 global $DB;
253 // Let's make a course.
254 $courseid = $this->make_course();
256 // Now let's make a couple modules on that course.
257 $cmid1 = $this->make_course_module($courseid, array(
258 'showavailability'=>1, 'availablefrom'=>17, 'availableuntil'=>398,
259 'completion'=>COMPLETION_TRACKING_MANUAL));
260 $cmid2 = $this->make_course_module($courseid, array(
261 'showavailability'=>0, 'availablefrom'=>0, 'availableuntil'=>0));
262 $this->make_section($courseid, array($cmid1, $cmid2), 1);
264 // Add a fake grade item.
265 $gradeitemid = $DB->insert_record('grade_items', (object)array(
266 'courseid'=>$courseid, 'itemname'=>'frog'));
268 // One of the modules has grade and completion conditions, other doesn't.
269 $DB->insert_record('course_modules_availability', (object)array(
270 'coursemoduleid'=>$cmid2,
271 'sourcecmid'=>$cmid1,
272 'requiredcompletion'=>1
274 $DB->insert_record('course_modules_availability', (object)array(
275 'coursemoduleid'=>$cmid2,
276 'gradeitemid'=>$gradeitemid,
277 'grademin'=>5.5
280 // Okay sweet, now get modinfo.
281 $modinfo = get_fast_modinfo($courseid);
283 // Test basic data.
284 $this->assertEquals(1, $modinfo->cms[$cmid1]->showavailability);
285 $this->assertEquals(17, $modinfo->cms[$cmid1]->availablefrom);
286 $this->assertEquals(398, $modinfo->cms[$cmid1]->availableuntil);
287 $this->assertEquals(0, $modinfo->cms[$cmid2]->showavailability);
288 $this->assertEquals(0, $modinfo->cms[$cmid2]->availablefrom);
289 $this->assertEquals(0, $modinfo->cms[$cmid2]->availableuntil);
291 // Test condition arrays.
292 $this->assertEquals(array(), $modinfo->cms[$cmid1]->conditionscompletion);
293 $this->assertEquals(array(), $modinfo->cms[$cmid1]->conditionsgrade);
294 $this->assertEquals(array($cmid1=>1),
295 $modinfo->cms[$cmid2]->conditionscompletion);
296 $this->assertEquals(array($gradeitemid=>(object)array('min'=>5.5, 'max'=>null, 'name'=>'frog')),
297 $modinfo->cms[$cmid2]->conditionsgrade);
300 public function test_section_modinfo() {
301 global $DB;
303 // Let's make a course.
304 $courseid = $this->make_course();
306 // Now let's make a couple sections on that course, one of which has a cm.
307 $cmid = $this->make_course_module($courseid);
308 $sectionid1 = $this->make_section($courseid, array($cmid), 1, array(
309 'showavailability' => 1, 'availablefrom' => 17,
310 'availableuntil' => 398, 'groupingid' => 13));
311 $sectionid2 = $this->make_section($courseid, array(), 2);
313 // Add a fake grade item.
314 $gradeitemid = $DB->insert_record('grade_items', (object)array(
315 'courseid' => $courseid, 'itemname' => 'frog'));
317 // One of the sections has grade and completion conditions, other doesn't.
318 $DB->insert_record('course_sections_availability', (object)array(
319 'coursesectionid' => $sectionid2,
320 'sourcecmid' => $cmid,
321 'requiredcompletion'=>1
323 $DB->insert_record('course_sections_availability', (object)array(
324 'coursesectionid' => $sectionid2,
325 'gradeitemid' => $gradeitemid,
326 'grademin' => 5.5
329 rebuild_course_cache($courseid, true);
330 // Okay sweet, now get modinfo.
331 $modinfo = get_fast_modinfo($courseid);
333 // Test basic data.
334 $section1 = $modinfo->get_section_info(1);
335 $this->assertEquals(1, $section1->showavailability);
336 $this->assertEquals(17, $section1->availablefrom);
337 $this->assertEquals(398, $section1->availableuntil);
338 $this->assertEquals(13, $section1->groupingid);
339 $section2 = $modinfo->get_section_info(2);
340 $this->assertEquals(0, $section2->showavailability);
341 $this->assertEquals(0, $section2->availablefrom);
342 $this->assertEquals(0, $section2->availableuntil);
343 $this->assertEquals(0, $section2->groupingid);
345 // Test condition arrays.
346 $this->assertEquals(array(), $section1->conditionscompletion);
347 $this->assertEquals(array(), $section1->conditionsgrade);
348 $this->assertEquals(array($cmid => 1),
349 $section2->conditionscompletion);
350 $this->assertEquals(array($gradeitemid => (object)array('min' => 5.5, 'max' => null, 'name' => 'frog')),
351 $section2->conditionsgrade);
354 public function test_add_and_remove() {
355 global $DB;
356 // Make course and module.
357 $courseid = $this->make_course();
358 $cmid = $this->make_course_module($courseid, array(
359 'showavailability'=>0, 'availablefrom'=>0, 'availableuntil'=>0));
360 $this->make_section($courseid, array($cmid), 1);
362 // Check it has no conditions.
363 $test1 = new condition_info((object)array('id'=>$cmid),
364 CONDITION_MISSING_EVERYTHING);
365 $cm = $test1->get_full_course_module();
366 $this->assertEquals(array(), $cm->conditionscompletion);
367 $this->assertEquals(array(), $cm->conditionsgrade);
369 // Add conditions of each type.
370 $test1->add_completion_condition(13, 3);
371 $this->assertEquals(array(13=>3), $cm->conditionscompletion);
372 $test1->add_grade_condition(666, 0.4, null, true);
373 $this->assertEquals(array(666=>(object)array('min'=>0.4, 'max'=>null, 'name'=>'!missing')),
374 $cm->conditionsgrade);
376 // Check they were really added in db.
377 $test2 = new condition_info((object)array('id'=>$cmid),
378 CONDITION_MISSING_EVERYTHING);
379 $cm = $test2->get_full_course_module();
380 $this->assertEquals(array(13=>3), $cm->conditionscompletion);
381 $this->assertEquals(array(666=>(object)array('min'=>0.4, 'max'=>null, 'name'=>'!missing')),
382 $cm->conditionsgrade);
384 // Wipe conditions.
385 $test2->wipe_conditions();
386 $this->assertEquals(array(), $cm->conditionscompletion);
387 $this->assertEquals(array(), $cm->conditionsgrade);
389 // Check they were really wiped.
390 $test3 = new condition_info((object)array('id'=>$cmid),
391 CONDITION_MISSING_EVERYTHING);
392 $cm = $test3->get_full_course_module();
393 $this->assertEquals(array(), $cm->conditionscompletion);
394 $this->assertEquals(array(), $cm->conditionsgrade);
397 public function test_section_add_and_remove() {
398 global $DB;
400 // Make course and module.
401 $courseid = $this->make_course();
402 $cmid = $this->make_course_module($courseid);
403 $sectionid = $this->make_section($courseid, array($cmid), 1);
405 // Check it has no conditions.
406 $test1 = new condition_info_section((object)array('id'=>$sectionid),
407 CONDITION_MISSING_EVERYTHING);
408 $section = $test1->get_full_section();
409 $this->assertEquals(array(), $section->conditionscompletion);
410 $this->assertEquals(array(), $section->conditionsgrade);
412 // Add conditions of each type.
413 $test1->add_completion_condition(13, 3);
414 $this->assertEquals(array(13 => 3), $section->conditionscompletion);
415 $test1->add_grade_condition(666, 0.4, null, true);
416 $this->assertEquals(array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing')),
417 $section->conditionsgrade);
419 // Check they were really added in db.
420 $test2 = new condition_info_section((object)array('id' => $sectionid),
421 CONDITION_MISSING_EVERYTHING);
422 $section = $test2->get_full_section();
423 $this->assertEquals(array(13 => 3), $section->conditionscompletion);
424 $this->assertEquals(array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing')),
425 $section->conditionsgrade);
427 // Wipe conditions.
428 $test2->wipe_conditions();
429 $this->assertEquals(array(), $section->conditionscompletion);
430 $this->assertEquals(array(), $section->conditionsgrade);
432 // Check they were really wiped.
433 $test3 = new condition_info_section((object)array('id' => $cmid),
434 CONDITION_MISSING_EVERYTHING);
435 $section = $test3->get_full_section();
436 $this->assertEquals(array(), $section->conditionscompletion);
437 $this->assertEquals(array(), $section->conditionsgrade);
440 public function test_is_available() {
441 global $DB, $USER;
442 $courseid = $this->make_course();
444 // No conditions.
445 $cmid = $this->make_course_module($courseid);
446 $ci = new condition_info((object)array('id'=>$cmid),
447 CONDITION_MISSING_EVERYTHING);
448 $this->assertTrue($ci->is_available($text, false, 0));
449 $this->assertEquals('', $text);
451 // Time (from).
452 $time = time()+100;
453 $cmid = $this->make_course_module($courseid, array('availablefrom'=>$time));
454 $ci = new condition_info((object)array('id'=>$cmid),
455 CONDITION_MISSING_EVERYTHING);
456 $this->assertFalse($ci->is_available($text));
457 $this->assertRegExp('/'.preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))).'/', $text);
459 $time = time()-100;
460 $cmid = $this->make_course_module($courseid, array('availablefrom'=>$time));
461 $ci = new condition_info((object)array('id'=>$cmid),
462 CONDITION_MISSING_EVERYTHING);
463 $this->assertTrue($ci->is_available($text));
464 $this->assertEquals('', $text);
465 $this->assertRegExp('/'.preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))).'/', $ci->get_full_information());
467 // Time (until).
468 $cmid = $this->make_course_module($courseid, array('availableuntil'=>time()-100));
469 $ci = new condition_info((object)array('id'=>$cmid),
470 CONDITION_MISSING_EVERYTHING);
471 $this->assertFalse($ci->is_available($text));
472 $this->assertEquals('', $text);
474 // Completion.
475 $oldid = $cmid;
476 $cmid = $this->make_course_module($courseid);
477 $this->make_section($courseid, array($oldid, $cmid), 1);
478 $oldcm = $DB->get_record('course_modules', array('id'=>$oldid));
479 $oldcm->completion = COMPLETION_TRACKING_MANUAL;
480 $DB->update_record('course_modules', $oldcm);
482 // Need to reset modinfo after changing the options.
483 rebuild_course_cache($courseid);
485 $ci = new condition_info((object)array('id'=>$cmid), CONDITION_MISSING_EVERYTHING);
486 $ci->add_completion_condition($oldid, COMPLETION_COMPLETE);
487 $this->wipe_condition_cache();
489 $this->assertFalse($ci->is_available($text, false));
490 $this->assertEquals(get_string('requires_completion_1', 'condition', 'xxx'), $text);
491 completion_info::wipe_session_cache();
492 $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
493 $completion->update_state($oldcm, COMPLETION_COMPLETE);
494 completion_info::wipe_session_cache();
495 $this->wipe_condition_cache();
497 $this->assertTrue($ci->is_available($text));
498 $this->assertFalse($ci->is_available($text, false, $USER->id+1));
499 completion_info::wipe_session_cache();
500 $this->wipe_condition_cache();
501 $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
502 $completion->update_state($oldcm, COMPLETION_INCOMPLETE);
503 $this->assertFalse($ci->is_available($text));
505 $ci->wipe_conditions();
506 $ci->add_completion_condition($oldid, COMPLETION_INCOMPLETE);
507 $this->wipe_condition_cache();
508 $this->assertTrue($ci->is_available($text));
509 $this->assertTrue($ci->is_available($text, false, $USER->id+1));
511 $this->wipe_condition_cache();
512 $this->assertTrue($ci->is_available($text, true));
514 // Grade.
515 $ci->wipe_conditions();
516 // Add a fake grade item.
517 $gradeitemid = $DB->insert_record('grade_items', (object)array(
518 'courseid'=>$courseid, 'itemname'=>'frog'));
519 // Add a condition on a value existing...
520 $ci->add_grade_condition($gradeitemid, null, null, true);
521 $this->assertFalse($ci->is_available($text));
522 $this->assertEquals(get_string('requires_grade_any', 'condition', 'frog'), $text);
524 // Fake it existing.
525 $DB->insert_record('grade_grades', (object)array(
526 'itemid'=>$gradeitemid, 'userid'=>$USER->id, 'finalgrade'=>3.78));
527 $this->wipe_condition_cache();
528 $this->assertTrue($ci->is_available($text));
530 $this->wipe_condition_cache();
531 $this->assertTrue($ci->is_available($text, true));
533 // Now require that user gets more than 3.78001.
534 $ci->wipe_conditions();
535 $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
536 $this->wipe_condition_cache();
537 $this->assertFalse($ci->is_available($text));
538 $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
540 // ...just on 3.78...
541 $ci->wipe_conditions();
542 $ci->add_grade_condition($gradeitemid, 3.78, null, true);
543 $this->wipe_condition_cache();
544 $this->assertTrue($ci->is_available($text));
546 // ...less than 3.78.
547 $ci->wipe_conditions();
548 $ci->add_grade_condition($gradeitemid, null, 3.78, true);
549 $this->wipe_condition_cache();
550 $this->assertFalse($ci->is_available($text));
551 $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
553 // ...less than 3.78001.
554 $ci->wipe_conditions();
555 $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
556 $this->wipe_condition_cache();
557 $this->assertTrue($ci->is_available($text));
559 // ...in a range that includes it.
560 $ci->wipe_conditions();
561 $ci->add_grade_condition($gradeitemid, 3, 4, true);
562 $this->wipe_condition_cache();
563 $this->assertTrue($ci->is_available($text));
565 // ...in a range that doesn't include it.
566 $ci->wipe_conditions();
567 $ci->add_grade_condition($gradeitemid, 4, 5, true);
568 $this->wipe_condition_cache();
569 $this->assertFalse($ci->is_available($text));
570 $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
573 public function test_section_is_available() {
574 global $DB, $USER;
575 $courseid = $this->make_course();
577 // Enrol user (needed for groups).
578 $enrolplugin = enrol_get_plugin('manual');
579 $course = $DB->get_record('course', array('id' => $courseid));
580 $enrolplugin->add_instance($course);
581 $enrolinstances = enrol_get_instances($courseid, false);
582 foreach ($enrolinstances as $enrolinstance) {
583 if ($enrolinstance->enrol === 'manual') {
584 break;
587 $enrolplugin->enrol_user($enrolinstance, $USER->id);
589 // Module for conditions later.
590 $cmid = $this->make_course_module($courseid);
592 // No conditions.
593 $sectionid = $this->make_section($courseid, array($cmid), 1);
594 $ci = new condition_info_section((object)array('id' => $sectionid),
595 CONDITION_MISSING_EVERYTHING);
596 $this->assertTrue($ci->is_available($text, false, 0));
597 $this->assertEquals('', $text);
599 // Time (from).
600 $time = time() + 100;
601 $sectionid = $this->make_section($courseid, array(), 2, array('availablefrom' => $time));
602 $ci = new condition_info_section((object)array('id' => $sectionid),
603 CONDITION_MISSING_EVERYTHING);
604 $this->assertFalse($ci->is_available($text));
605 $timetext = userdate($time, get_string('strftimedate', 'langconfig'));
606 $this->assertRegExp('~' . preg_quote($timetext) . '~', $text);
608 $time = time()-100;
609 $sectionid = $this->make_section($courseid, array(), 3, array('availablefrom' => $time));
610 $ci = new condition_info_section((object)array('id' => $sectionid),
611 CONDITION_MISSING_EVERYTHING);
612 $this->assertTrue($ci->is_available($text));
613 $this->assertEquals('', $text);
614 $timetext = userdate($time, get_string('strftimedate', 'langconfig'));
615 $this->assertRegExp('~' . preg_quote($timetext) . '~', $ci->get_full_information());
617 // Time (until).
618 $sectionid = $this->make_section($courseid, array(), 4, array('availableuntil' => time() - 100));
619 $ci = new condition_info_section((object)array('id' => $sectionid),
620 CONDITION_MISSING_EVERYTHING);
621 $this->assertFalse($ci->is_available($text));
622 $this->assertEquals('', $text);
624 // Completion: first set up cm.
625 $sectionid = $this->make_section($courseid, array(), 5);
626 $cm = $DB->get_record('course_modules', array('id' => $cmid));
627 $cm->completion = COMPLETION_TRACKING_MANUAL;
628 $DB->update_record('course_modules', $cm);
630 // Completion: Reset modinfo after changing the options.
631 rebuild_course_cache($courseid);
633 // Completion: Add condition.
634 $ci = new condition_info_section((object)array('id' => $sectionid),
635 CONDITION_MISSING_EVERYTHING);
636 $ci->add_completion_condition($cmid, COMPLETION_COMPLETE);
637 $this->wipe_condition_cache();
639 // Completion: Check.
640 $this->assertFalse($ci->is_available($text, false));
641 $this->assertEquals(get_string('requires_completion_1', 'condition', 'xxx'), $text);
642 completion_info::wipe_session_cache();
643 $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
644 $completion->update_state($cm, COMPLETION_COMPLETE);
645 completion_info::wipe_session_cache();
646 $this->wipe_condition_cache();
647 $this->assertTrue($ci->is_available($text));
648 $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
650 // Completion: Uncheck.
651 completion_info::wipe_session_cache();
652 $this->wipe_condition_cache();
653 $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
654 $completion->update_state($cm, COMPLETION_INCOMPLETE);
655 $this->assertFalse($ci->is_available($text));
657 // Completion: Incomplete condition.
658 $ci->wipe_conditions();
659 $ci->add_completion_condition($cmid, COMPLETION_INCOMPLETE);
660 $this->wipe_condition_cache();
661 $this->assertTrue($ci->is_available($text));
662 $this->assertTrue($ci->is_available($text, false, $USER->id + 1));
663 $this->wipe_condition_cache();
664 $this->assertTrue($ci->is_available($text, true));
666 // Grade: Add a fake grade item.
667 $gradeitemid = $DB->insert_record('grade_items', (object)array(
668 'courseid' => $courseid, 'itemname' => 'frog'));
670 // Grade: Add a condition on a value existing.
671 $ci->wipe_conditions();
672 $ci->add_grade_condition($gradeitemid, null, null, true);
673 $this->assertFalse($ci->is_available($text));
674 $this->assertEquals(get_string('requires_grade_any', 'condition', 'frog'), $text);
676 // Grade: Fake it existing.
677 $DB->insert_record('grade_grades', (object)array(
678 'itemid' => $gradeitemid, 'userid' => $USER->id, 'finalgrade' => 3.78));
679 $this->wipe_condition_cache();
680 $this->assertTrue($ci->is_available($text));
681 $this->wipe_condition_cache();
682 $this->assertTrue($ci->is_available($text, true));
684 // Grade: Now require that user gets more than 3.78001.
685 $ci->wipe_conditions();
686 $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
687 $this->wipe_condition_cache();
688 $this->assertFalse($ci->is_available($text));
689 $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
691 // Grade: ...just on 3.78...
692 $ci->wipe_conditions();
693 $ci->add_grade_condition($gradeitemid, 3.78, null, true);
694 $this->wipe_condition_cache();
695 $this->assertTrue($ci->is_available($text));
697 // Grade: ...less than 3.78.
698 $ci->wipe_conditions();
699 $ci->add_grade_condition($gradeitemid, null, 3.78, true);
700 $this->wipe_condition_cache();
701 $this->assertFalse($ci->is_available($text));
702 $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
704 // Grade: ...less than 3.78001.
705 $ci->wipe_conditions();
706 $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
707 $this->wipe_condition_cache();
708 $this->assertTrue($ci->is_available($text));
710 // Grade: ...in a range that includes it.
711 $ci->wipe_conditions();
712 $ci->add_grade_condition($gradeitemid, 3, 4, true);
713 $this->wipe_condition_cache();
714 $this->assertTrue($ci->is_available($text));
716 // Grade: ...in a range that doesn't include it.
717 $ci->wipe_conditions();
718 $ci->add_grade_condition($gradeitemid, 4, 5, true);
719 $this->wipe_condition_cache();
720 $this->assertFalse($ci->is_available($text));
721 $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
723 // Grouping: Not member.
724 $groupingid = $this->make_grouping($courseid, 'Grouping');
725 $groupid = $this->make_group($courseid, 'Group', $groupingid);
726 $sectionid = $this->make_section($courseid, array(), 6, array('groupingid' => $groupingid));
727 $ci = new condition_info_section((object)array('id' => $sectionid),
728 CONDITION_MISSING_EVERYTHING);
729 $this->assertFalse($ci->is_available($text));
730 $this->assertEquals(trim(get_string('groupingnoaccess', 'condition')), $text);
732 // Grouping: Member.
733 $this->assertTrue(groups_add_member($groupid, $USER->id));
735 condition_info_section::init_global_cache();
736 $this->assertTrue($ci->is_available($text));
737 $this->assertEquals('', $text);
738 $this->assertTrue($ci->is_available($text, true));
740 // Grouping: Somebody else.
741 $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
742 $this->assertFalse($ci->is_available($text, true, $USER->id + 1));
746 * Tests user fields to ensure that the list of provided fields includes only
747 * fields which the equivalent function can be used to obtain the value of.
749 public function test_condition_user_fields() {
750 global $CFG, $DB, $USER;
752 // Set up basic data.
753 $courseid = $this->make_course();
754 $cmid = $this->make_course_module($courseid);
755 $ci = new condition_info_testwrapper(
756 (object)array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
758 // Add a custom user profile field. Unfortunately there is no back-end
759 // API for adding profile fields without having an actual form and doing
760 // redirects and stuff! These are the default text field parameters.
761 require_once($CFG->dirroot . '/user/profile/lib.php');
762 $field = (object)array(
763 'shortname' => 'myfield', 'name' => 'My field', 'required' => 0,
764 'locked' => 0, 'forceunique' => 0, 'signup' => 0,
765 'visible' => PROFILE_VISIBLE_ALL,
766 'datatype' => 'text', 'description' => 'A field of mine',
767 'descriptionformat' => FORMAT_HTML, 'defaultdata' => '',
768 'defaultdataformat' => FORMAT_HTML, 'param1' => 30, 'param2' => 2048,
769 'param3' => 0, 'param4' => '', 'param5' => '');
770 $customfieldid = $DB->insert_record('user_info_field', $field);
772 // Get list of condition user fields.
773 $fields = condition_info::get_condition_user_fields();
775 // Check custom field is included.
776 $this->assertEquals('My field', $fields[$customfieldid]);
778 // For all other fields, check it actually works to get data from them.
779 foreach ($fields as $fieldid => $name) {
780 // Not checking the result, just that it's possible to get it
781 // without error.
782 $ci->inspect_get_cached_user_profile_field($USER->id, $fieldid);
785 // Change to not logged in user.
786 $this->setUser(null);
788 foreach ($fields as $fieldid => $name) {
789 // Should get false always when not logged in.
790 $this->assertEquals(false, $ci->inspect_get_cached_user_profile_field($USER->id, $fieldid));
797 * Test wrapper used only to make protected functions public so they can be
798 * tested.
800 class condition_info_testwrapper extends condition_info {
801 public function inspect_get_cached_user_profile_field($userid, $fieldid) {
802 return parent::get_cached_user_profile_field($userid, $fieldid);