MDL-16520 - make the already exporting portfolio error more user friendly
[moodle.git] / lib / simpletest / testcompletionlib.php
CommitLineData
4e781c7b 1<?php
2if (!defined('MOODLE_INTERNAL')) {
3 die('Direct access to this script is forbidden.');
4}
5require_once($CFG->libdir.'/completionlib.php');
6
7global $DB;
8Mock::generate(get_class($DB), 'mock_database');
9
10Mock::generatePartial('completion_info','completion_cutdown',
11 array('delete_all_state','internal_get_tracked_users','update_state',
12 'internal_get_grade_state','is_enabled','get_data','internal_get_state','internal_set_data'));
13Mock::generatePartial('completion_info','completion_cutdown2',
14 array('is_enabled','get_data','internal_get_state','internal_set_data'));
15Mock::generatePartial('completion_info','completion_cutdown3',
16 array('internal_get_grade_state'));
17
18class fake_recordset implements Iterator {
19 var $closed;
20 var $values,$index;
21
22 function fake_recordset($values) {
23 $this->values=$values;
24 $this->index=0;
25 }
26
27 function current() {
28 return $this->values[$this->index];
29 }
30
31 function key() {
32 return $this->values[$this->index];
33 }
34
35 function next() {
36 $this->index++;
37 }
38
39 function rewind() {
40 $this->index=0;
41 }
42
43 function valid() {
44 return count($this->values) > $this->index;
45 }
46
47 function close() {
48 $closed=true;
49 }
50
51 function was_closed() {
52 return $closed;
53 }
54}
55
56/**
57 * Expectation that checks an object for given values (normal equality test)
58 * plus a 'timemodified' field that is current (last second or two).
59 */
60class TimeModifiedExpectation extends SimpleExpectation {
61 private $otherfields;
62
63 /**
64 * @param array $otherfields Array key=>value of required object fields
65 */
66 function TimeModifiedExpectation($otherfields) {
67 $this->otherfields=$otherfields;
68 }
69
70 function test($thing) {
71 $thingfields=(array)$thing;
72 foreach($this->otherfields as $key=>$value) {
73 if(!array_key_exists($key,$thingfields)) {
74 return false;
75 }
76 if($thingfields[$key]!=$value) {
77 return false;
78 }
79 }
80
81 $timedifference=time()-$thing->timemodified;
82 return ($timedifference < 2 && $timedifference>=0);
83 }
84
85 function testMessage($thing) {
86 return "Object does not match fields/time requirement";
87 }
88}
89
90class completionlib_test extends UnitTestCase {
91 var $realdb,$realcfg,$realsession,$realuser;
92
93 function setUp() {
94 global $DB,$CFG,$SESSION,$USER;
95 $this->realdb=$DB;
96 $this->realcfg=$CFG;
97 $this->realuser=$USER;
98 $DB=new mock_database();
99 $CFG=clone($this->realcfg);
100 $CFG->prefix='test_';
101 $CFG->enablecompletion=COMPLETION_ENABLED;
102 $SESSION=new stdClass();
103 $USER=(object)array('id'=>314159);
104 }
105
106 function tearDown() {
107 global $DB,$CFG,$SESSION,$USER;
108 $DB=$this->realdb;
109 $CFG=$this->realcfg;
110 $SESSION=$this->realsession;
111 $USER=$this->realuser;
112 }
113
114 function test_is_enabled() {
115 global $CFG;
116
117 // Config alone
118 $CFG->enablecompletion=COMPLETION_DISABLED;
119 $this->assertEqual(COMPLETION_DISABLED,completion_info::is_enabled_for_site());
120 $CFG->enablecompletion=COMPLETION_ENABLED;
121 $this->assertEqual(COMPLETION_ENABLED,completion_info::is_enabled_for_site());
122
123 // Course
124 $course=new stdClass;
125 $c=new completion_info($course);
126 $course->enablecompletion=COMPLETION_DISABLED;
127 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled());
128 $course->enablecompletion=COMPLETION_ENABLED;
129 $this->assertEqual(COMPLETION_ENABLED,$c->is_enabled());
130 $CFG->enablecompletion=COMPLETION_DISABLED;
131 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled());
132
133 // Course and CM
134 $cm=new stdClass;
135 $cm->completion=COMPLETION_TRACKING_MANUAL;
136 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm));
137 $CFG->enablecompletion=COMPLETION_ENABLED;
138 $course->enablecompletion=COMPLETION_DISABLED;
139 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm));
140 $course->enablecompletion=COMPLETION_ENABLED;
141 $this->assertEqual(COMPLETION_TRACKING_MANUAL,$c->is_enabled($cm));
142 $cm->completion=COMPLETION_TRACKING_NONE;
143 $this->assertEqual(COMPLETION_TRACKING_NONE,$c->is_enabled($cm));
144 $cm->completion=COMPLETION_TRACKING_AUTOMATIC;
145 $this->assertEqual(COMPLETION_TRACKING_AUTOMATIC,$c->is_enabled($cm));
146 }
147
148 function test_update_state() {
149 $c=new completion_cutdown2();
49f6e5f4 150 $c->__construct((object)array('id'=>42));
4e781c7b 151 $cm=(object)array('id'=>13,'course'=>42);
152
153 // Not enabled, should do nothing
154 $c->expectAt(0,'is_enabled',array($cm));
155 $c->setReturnValueAt(0,'is_enabled',false);
156 $c->update_state($cm);
157
158 // Enabled, but current state is same as possible result, do nothing
159 $current=(object)array('completionstate'=>COMPLETION_COMPLETE);
160 $c->expectAt(1,'is_enabled',array($cm));
161 $c->setReturnValueAt(1,'is_enabled',true);
162
163 $c->expectAt(0,'get_data',array($cm,false,0));
164 $c->setReturnValueAt(0,'get_data',$current);
165 $c->update_state($cm,COMPLETION_COMPLETE);
166
167 // Enabled, but current state is a specific one and new state is just
168 // omplete, so do nothing
169 $current->completionstate=COMPLETION_COMPLETE_PASS;
170 $c->expectAt(2,'is_enabled',array($cm));
171 $c->setReturnValueAt(2,'is_enabled',true);
172 $c->expectAt(1,'get_data',array($cm,false,0));
173 $c->setReturnValueAt(1,'get_data',$current);
174 $c->update_state($cm,COMPLETION_COMPLETE);
175
176 // Manual, change state (no change)
177 $cm->completion=COMPLETION_TRACKING_MANUAL;
178 $current->completionstate=COMPLETION_COMPLETE;
179 $c->expectAt(3,'is_enabled',array($cm));
180 $c->setReturnValueAt(3,'is_enabled',true);
181 $c->expectAt(2,'get_data',array($cm,false,0));
182 $c->setReturnValueAt(2,'get_data',$current);
183 $c->update_state($cm,COMPLETION_COMPLETE);
184
185 // Manual, change state (change)
186 $c->expectAt(4,'is_enabled',array($cm));
187 $c->setReturnValueAt(4,'is_enabled',true);
188 $c->expectAt(3,'get_data',array($cm,false,0));
189 $c->setReturnValueAt(3,'get_data',$current);
190 $c->expectAt(0,'internal_set_data',array($cm,
191 new TimeModifiedExpectation(array('completionstate'=>COMPLETION_INCOMPLETE))));
192 $c->update_state($cm,COMPLETION_INCOMPLETE);
193
194 // Auto, change state
195 $cm->completion=COMPLETION_TRACKING_AUTOMATIC;
196 $c->expectAt(5,'is_enabled',array($cm));
197 $c->setReturnValueAt(5,'is_enabled',true);
198 $c->expectAt(4,'get_data',array($cm,false,0));
199 $c->setReturnValueAt(4,'get_data',$current);
200 $c->expectAt(0,'internal_get_state',array($cm,0,$current));
201 $c->setReturnValueAt(0,'internal_get_state',COMPLETION_COMPLETE_PASS);
202 $c->expectAt(1,'internal_set_data',array($cm,
203 new TimeModifiedExpectation(array('completionstate'=>COMPLETION_COMPLETE_PASS))));
204 $c->update_state($cm,COMPLETION_COMPLETE_PASS);
205
206 $c->tally();
207 }
208
209 function test_internal_get_state() {
210 global $DB;
211
212 $c=new completion_cutdown3();
49f6e5f4 213 $c->__construct((object)array('id'=>42));
4e781c7b 214 $cm=(object)array('id'=>13,'course'=>42,'completiongradeitemnumber'=>null);
215
216 // If view is required, but they haven't viewed it yet
217 $cm->completionview=COMPLETION_VIEW_REQUIRED;
218 $current=(object)array('viewed'=>COMPLETION_NOT_VIEWED);
219 $this->assertEqual(COMPLETION_INCOMPLETE,$c->internal_get_state($cm,123,$current));
220
221 // OK set view not required
222 $cm->completionview=COMPLETION_VIEW_NOT_REQUIRED;
223
224 // Test not getting module name
225 $cm->modname='label';
226 $this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current));
227
228 // Test getting module name
229 $cm->module=13;
230 unset($cm->modname);
231 $DB->expectOnce('get_field',array('modules','name',array('id'=>13)));
232 $DB->setReturnValue('get_field','label');
233 $this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current));
234
235 // Note: This function is not fully tested (including kind of the main
236 // part) because:
237 // * the grade_item/grade_grade calls are static and can't be mocked
238 // * the plugin_supports call is static and can't be mocked
239
240 $DB->tally();
241 $c->tally();
242 }
243
244 function test_set_module_viewed() {
245 $c=new completion_cutdown();
49f6e5f4 246 $c->__construct((object)array('id'=>42));
4e781c7b 247 $cm=(object)array('id'=>13,'course'=>42);
248
249 // Not tracking completion, should do nothing
250 $cm->completionview=COMPLETION_VIEW_NOT_REQUIRED;
251 $c->set_module_viewed($cm);
252
253 // Tracking completion but completion is disabled, should do nothing
254 $cm->completionview=COMPLETION_VIEW_REQUIRED;
255 $c->expectAt(0,'is_enabled',array($cm));
256 $c->setReturnValueAt(0,'is_enabled',false);
257 $c->set_module_viewed($cm);
258
259 // Now it's enabled, we expect it to get data. If data already has
260 // viewed, still do nothing
261 $c->expectAt(1,'is_enabled',array($cm));
262 $c->setReturnValueAt(1,'is_enabled',true);
263 $c->expectAt(0,'get_data',array($cm,0));
264 $hasviewed=(object)array('viewed'=>COMPLETION_VIEWED);
265 $c->setReturnValueAt(0,'get_data',$hasviewed);
266 $c->set_module_viewed($cm);
267
268 // OK finally one that hasn't been viewed, now it should set it viewed
269 // and update state
270 $c->expectAt(2,'is_enabled',array($cm));
271 $c->setReturnValueAt(2,'is_enabled',true);
272 $notviewed=(object)array('viewed'=>COMPLETION_NOT_VIEWED);
273 $c->expectAt(1,'get_data',array($cm,1337));
274 $c->setReturnValueAt(1,'get_data',$notviewed);
275 $c->expectOnce('internal_set_data',array($cm,$hasviewed));
276 $c->expectOnce('update_state',array($cm,COMPLETION_COMPLETE,1337));
277 $c->set_module_viewed($cm,1337);
278
279 $c->tally();
280 }
281
282 function test_count_user_data() {
283 global $DB;
284 $cm=(object)array('id'=>42);
285 $DB->setReturnValue('get_field_sql',666);
286 $DB->expectOnce('get_field_sql',array(new IgnoreWhitespaceExpectation("SELECT
287 COUNT(1)
288FROM
49f6e5f4 289 {course_modules_completion}
4e781c7b 290WHERE
291 coursemoduleid=? AND completionstate<>0"),array(42)));
292 $c=new completion_info(null);
293 $this->assertEqual(666,$c->count_user_data($cm));
294
295 $DB->tally();
296 }
297
298 function test_delete_all_state() {
299 global $DB,$SESSION;
300 $course=(object)array('id'=>13);
301 $cm=(object)array('id'=>42,'course'=>13);
302 $c=new completion_info($course);
303 // Check it works ok without data in session
304 $DB->expectAt(0,'delete_records',
305 array('course_modules_completion',array('coursemoduleid'=>42)));
306 $c->delete_all_state($cm);
307
308 // Build up a session to check it deletes the right bits from it
309 // (and not other bits)
310 $SESSION->completioncache=array();
311 $SESSION->completioncache[13]=array();
312 $SESSION->completioncache[13][42]='foo';
313 $SESSION->completioncache[13][43]='foo';
314 $SESSION->completioncache[14]=array();
315 $SESSION->completioncache[14][42]='foo';
316 $DB->expectAt(1,'delete_records',
317 array('course_modules_completion',array('coursemoduleid'=>42)));
318 $c->delete_all_state($cm);
319 $this->assertEqual(array(13=>array(43=>'foo'),14=>array(42=>'foo')),
320 $SESSION->completioncache);
321
322 $DB->tally();
323 }
324
325 function test_reset_all_state() {
326 global $DB;
327 $c=new completion_cutdown();
49f6e5f4 328 $c->__construct((object)array('id'=>42));
4e781c7b 329
330 $cm=(object)array('id'=>13,'course'=>42);
331
332 $DB->setReturnValue('get_recordset',new fake_recordset(array(
333 (object)array('id'=>1,'userid'=>100),
334 (object)array('id'=>2,'userid'=>101),
335 )));
336 $DB->expectOnce('get_recordset',array('course_modules_completion',
337 array('coursemoduleid'=>13),'','userid'));
338 $c->expectOnce('delete_all_state',array($cm));
339 $c->expectOnce('internal_get_tracked_users',array(false));
340 $c->setReturnValue('internal_get_tracked_users',array(
341 (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'),
342 (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'),
343 ));
344
345 $c->expectAt(0,'update_state',array($cm,COMPLETION_UNKNOWN,100));
346 $c->expectAt(1,'update_state',array($cm,COMPLETION_UNKNOWN,101));
347 $c->expectAt(2,'update_state',array($cm,COMPLETION_UNKNOWN,201));
348
349 $c->reset_all_state($cm);
350
351 $DB->tally();
352 $c->tally();
353 }
354
355 function test_get_data() {
356 global $DB,$SESSION;
357
358 $c=new completion_info((object)array('id'=>42));
359 $cm=(object)array('id'=>13,'course'=>42);
360
361 // 1. Not current user, record exists
362 $sillyrecord=(object)array('frog'=>'kermit');
363 $DB->expectAt(0,'get_record',array('course_modules_completion',
364 array('coursemoduleid'=>13,'userid'=>123)));
365 $DB->setReturnValueAt(0,'get_record',$sillyrecord);
366 $result=$c->get_data($cm,false,123);
367 $this->assertEqual($sillyrecord,$result);
368 $this->assertTrue(empty($SESSION->completioncache));
369
370 // 2. Not current user, default record, wholecourse (ignored)
371 $DB->expectAt(1,'get_record',array('course_modules_completion',
372 array('coursemoduleid'=>13,'userid'=>123)));
373 $DB->setReturnValueAt(1,'get_record',false);
374 $result=$c->get_data($cm,true,123);
375 $this->assertEqual((object)array(
376 'id'=>'0','coursemoduleid'=>13,'userid'=>123,'completionstate'=>0,
377 'viewed'=>0,'timemodified'=>0),$result);
378 $this->assertTrue(empty($SESSION->completioncache));
379
380 // 3. Current user, single record, not from cache
381 $DB->expectAt(2,'get_record',array('course_modules_completion',
382 array('coursemoduleid'=>13,'userid'=>314159)));
383 $DB->setReturnValueAt(2,'get_record',$sillyrecord);
384 $result=$c->get_data($cm);
385 $this->assertEqual($sillyrecord,$result);
386 $this->assertEqual($sillyrecord,$SESSION->completioncache[42][13]);
387 // When checking time(), allow for second overlaps
388 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
389
390 // 4. Current user, 'whole course', but from cache
391 $result=$c->get_data($cm,true);
392 $this->assertEqual($sillyrecord,$result);
393
394 // 5. Current user, single record, cache expired
395 $SESSION->completioncache[42]['updated']=37; // Quite a long time ago
396 $now=time();
397 $SESSION->completioncache[17]['updated']=$now;
398 $SESSION->completioncache[39]['updated']=72; // Also a long time ago
399 $DB->expectAt(3,'get_record',array('course_modules_completion',
400 array('coursemoduleid'=>13,'userid'=>314159)));
401 $DB->setReturnValueAt(3,'get_record',$sillyrecord);
402 $result=$c->get_data($cm,false);
403 $this->assertEqual($sillyrecord,$result);
404 // Check that updated value is right, then fudge it to make next compare
405 // work
406 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
407 $SESSION->completioncache[42]['updated']=$now;
408 // Check things got expired from cache
409 $this->assertEqual(array(42=>array(13=>$sillyrecord,'updated'=>$now),
410 17=>array('updated'=>$now)),$SESSION->completioncache);
411
412 // 6. Current user, 'whole course' and record not in cache
413 unset($SESSION->completioncache);
414
415 // Scenario: Completion data exists for one CMid
416 $basicrecord=(object)array('coursemoduleid'=>13);
417 $DB->setReturnValueAt(0,'get_records_sql',array(
418 1=>$basicrecord
419 ));
420 $DB->expectAt(0,'get_records_sql',array(new IgnoreWhitespaceExpectation("
421SELECT
422 cmc.*
423FROM
49f6e5f4 424 {course_modules} cm
425 INNER JOIN {course_modules_completion} cmc ON cmc.coursemoduleid=cm.id
4e781c7b 426WHERE
427 cm.course=? AND cmc.userid=?"),array(42,314159)));
428
429 // There are two CMids in total, the one we had data for and another one
430 $modinfo->cms=array((object)array('id'=>13),(object)array('id'=>14));
431 $result=$c->get_data($cm,true,0,$modinfo);
432
433 // Check result
434 $this->assertEqual($basicrecord,$result);
435
436 // Check the cache contents
437 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
438 $SESSION->completioncache[42]['updated']=$now;
439 $this->assertEqual(array(42=>array(13=>$basicrecord,14=>(object)array(
440 'id'=>'0','coursemoduleid'=>14,'userid'=>314159,'completionstate'=>0,
441 'viewed'=>0,'timemodified'=>0),'updated'=>$now)),$SESSION->completioncache);
442
443 $DB->tally();
444 }
445
446 function test_internal_set_data() {
447 global $DB,$SESSION;
448
449 $cm=(object)array('course'=>42,'id'=>13);
450 $c=new completion_info((object)array('id'=>42));
451
452 // 1) Test with new data
453 $data=(object)array('id'=>0,'userid'=>314159);
454 $DB->setReturnValueAt(0,'insert_record',4);
455 $DB->expectAt(0,'insert_record',array('course_modules_completion',$data));
456 $c->internal_set_data($cm,$data);
457 $this->assertEqual(4,$data->id);
458 $this->assertEqual(array(42=>array(13=>$data)),$SESSION->completioncache);
459
460 // 2) Test with existing data and for different user (not cached)
461 unset($SESSION->completioncache);
462 $d2=(object)array('id'=>7,'userid'=>17);
463 $DB->expectAt(0,'update_record',array('course_modules_completion',$d2));
464 $c->internal_set_data($cm,$d2);
465 $this->assertFalse(isset($SESSION->completioncache));
466
467 $DB->tally();
468 }
469
470 function test_get_activities() {
471 global $DB;
472
473 $c=new completion_info((object)array('id'=>42));
474
475 // Try with no activities
476 $DB->expectAt(0,'get_records_select',array('course_modules',
477 'course=42 AND completion<>'.COMPLETION_TRACKING_NONE));
478 $DB->setReturnValueAt(0,'get_records_select',array());
479 $result=$c->get_activities();
480 $this->assertEqual(array(),$result);
481
482 // Try with an activity (need to fake up modinfo for it as well)
483 $DB->expectAt(1,'get_records_select',array('course_modules',
484 'course=42 AND completion<>'.COMPLETION_TRACKING_NONE));
485 $DB->setReturnValueAt(1,'get_records_select',array(
486 13=>(object)array('id'=>13)
487 ));
488 $modinfo=new stdClass;
489 $modinfo->sections=array(array(1,2,3),array(12,13,14));
490 $modinfo->cms[13]=(object)array('modname'=>'frog','name'=>'kermit');
491 $result=$c->get_activities($modinfo);
492 $this->assertEqual(array(13=>(object)array('id'=>13,'modname'=>'frog','name'=>'kermit')),$result);
493
494 $DB->tally();
495 }
496
497 // internal_get_tracked_users() cannot easily be tested because it uses
498 // get_role_users, so skipping that
499
500 function test_get_progress_all() {
501 global $DB;
502
503 $c=new completion_cutdown();
49f6e5f4 504 $c->__construct((object)array('id'=>42));
4e781c7b 505
506 // 1) Basic usage
507 $c->expectAt(0,'internal_get_tracked_users',array(false,0));
508 $c->setReturnValueAt(0,'internal_get_tracked_users',array(
509 (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'),
510 (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'),
511 ));
512 $DB->expectAt(0,'get_in_or_equal',array(array(100,201)));
513 $DB->setReturnValueAt(0,'get_in_or_equal',array(' IN (100,201)',array()));
514 $DB->expectAt(0,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
515SELECT
516 cmc.*
517FROM
49f6e5f4 518 {course_modules} cm
519 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
4e781c7b 520WHERE
521 cm.course=? AND cmc.userid IN (100,201)"),array(42)));
522 $progress1=(object)array('userid'=>100,'coursemoduleid'=>13);
523 $progress2=(object)array('userid'=>201,'coursemoduleid'=>14);
524 $DB->setReturnValueAt(0,'get_recordset_sql',new fake_recordset(array(
525 $progress1,$progress2
526 )));
527
528 $this->assertEqual(array(
529 100 => (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh',
530 'progress'=>array(13=>$progress1)),
531 201 => (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy',
532 'progress'=>array(14=>$progress2)),
533 ),$c->get_progress_all(false));
534
535 // 2) With more than 1,000 results
536 $c->expectAt(1,'internal_get_tracked_users',array(true,3));
537
538 $tracked=array();
539 $ids=array();
540 $progress=array();
541 for($i=100;$i<2000;$i++) {
542 $tracked[]=(object)array('id'=>$i,'firstname'=>'frog','lastname'=>$i);
543 $ids[]=$i;
544 $progress[]=(object)array('userid'=>$i,'coursemoduleid'=>13);
545 $progress[]=(object)array('userid'=>$i,'coursemoduleid'=>14);
546 }
547 $c->setReturnValueAt(1,'internal_get_tracked_users',$tracked);
548
549 $DB->expectAt(1,'get_in_or_equal',array(array_slice($ids,0,1000)));
550 $DB->setReturnValueAt(1,'get_in_or_equal',array(' IN whatever',array()));
551 $DB->expectAt(1,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
552SELECT
553 cmc.*
554FROM
49f6e5f4 555 {course_modules} cm
556 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
4e781c7b 557WHERE
558 cm.course=? AND cmc.userid IN whatever"),array(42)));
559 $DB->setReturnValueAt(1,'get_recordset_sql',new fake_recordset(array_slice($progress,0,1000)));
560 $DB->expectAt(2,'get_in_or_equal',array(array_slice($ids,1000)));
561 $DB->setReturnValueAt(2,'get_in_or_equal',array(' IN whatever2',array()));
562 $DB->expectAt(2,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
563SELECT
564 cmc.*
565FROM
49f6e5f4 566 {course_modules} cm
567 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
4e781c7b 568WHERE
569 cm.course=? AND cmc.userid IN whatever2"),array(42)));
570 $DB->setReturnValueAt(2,'get_recordset_sql',new fake_recordset(array_slice($progress,1000)));
571
572 $result=$c->get_progress_all(true,3);
573
574 $resultok=true;
575 $resultok = $resultok && ($ids==array_keys($result));
576 foreach($result as $userid => $data) {
577 $resultok = $resultok && $data->firstname=='frog';
578 $resultok = $resultok && $data->lastname==$userid;
579 $resultok = $resultok && $data->id==$userid;
580 $cms=$data->progress;
581 $resultok= $resultok && (array(13,14)==array_keys($cms));
582 $resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>13)==$cms[13]);
583 $resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>14)==$cms[14]);
584 }
585 $this->assertTrue($resultok);
586
587 $DB->tally();
588 $c->tally();
589 }
590
591 function test_inform_grade_changed() {
592 $c=new completion_cutdown();
49f6e5f4 593 $c->__construct((object)array('id'=>42));
4e781c7b 594
595 $cm=(object)array('course'=>42,'id'=>13,'completiongradeitemnumber'=>null);
596 $item=(object)array('itemnumber'=>3);
597 $grade=(object)array('userid'=>31337);
598
599 // Not enabled (should do nothing)
600 $c->setReturnValueAt(0,'is_enabled',false);
601 $c->expectAt(0,'is_enabled',array($cm));
602 $c->inform_grade_changed($cm,$item,$grade,false);
603
604 // Enabled but still no grade completion required, should still do nothing
605 $c->setReturnValueAt(1,'is_enabled',true);
606 $c->expectAt(1,'is_enabled',array($cm));
607 $c->inform_grade_changed($cm,$item,$grade,false);
608
609 // Enabled and completion required but item number is wrong, does nothing
610 $cm->completiongradeitemnumber=7;
611 $c->setReturnValueAt(2,'is_enabled',true);
612 $c->expectAt(2,'is_enabled',array($cm));
613 $c->inform_grade_changed($cm,$item,$grade,false);
614
615 // Enabled and completion required and item number right. It is supposed
616 // to call update_state with the new potential state being obtained from
617 // internal_get_grade_state.
618 $cm->completiongradeitemnumber=3;
619 $c->setReturnValueAt(3,'is_enabled',true);
620 $c->expectAt(3,'is_enabled',array($cm));
621 $c->expectAt(0,'internal_get_grade_state',array($item,$grade));
622 $c->setReturnValueAt(0,'internal_get_grade_state',COMPLETION_COMPLETE_PASS);
623 $c->expectAt(0,'update_state',array($cm,COMPLETION_COMPLETE_PASS,31337));
624 $c->inform_grade_changed($cm,$item,$grade,false);
625
626 // Same as above but marked deleted. It is supposed to call update_state
627 // with new potential state being COMPLETION_INCOMPLETE
628 $c->setReturnValueAt(4,'is_enabled',false);
629 $c->expectAt(4,'is_enabled',array($cm));
630 $c->expectAt(1,'update_state',array($cm,COMPLETION_INCOMPLETE,31337));
631 $c->inform_grade_changed($cm,$item,$grade,false);
632
633 $c->tally();
634 }
635
636 function test_internal_get_grade_state() {
637 $item=new stdClass;
638 $grade=new stdClass;
639
640 $item->gradepass=4;
641 $item->hidden=0;
642 $grade->rawgrade=4.0;
643 $grade->finalgrade=null;
644
645 // Grade has pass mark and is not hidden, user passes
646 $this->assertEqual(
647 COMPLETION_COMPLETE_PASS,
648 completion_info::internal_get_grade_state($item,$grade));
649
650 // Same but user fails
651 $grade->rawgrade=3.9;
652 $this->assertEqual(
653 COMPLETION_COMPLETE_FAIL,
654 completion_info::internal_get_grade_state($item,$grade));
655
656 // User fails on raw grade but passes on final
657 $grade->finalgrade=4.0;
658 $this->assertEqual(
659 COMPLETION_COMPLETE_PASS,
660 completion_info::internal_get_grade_state($item,$grade));
661
662 // Item is hidden
663 $item->hidden=1;
664 $this->assertEqual(
665 COMPLETION_COMPLETE,
666 completion_info::internal_get_grade_state($item,$grade));
667
668 // Item isn't hidden but has no pass mark
669 $item->hidden=0;
670 $item->gradepass=0;
671 $this->assertEqual(
672 COMPLETION_COMPLETE,
673 completion_info::internal_get_grade_state($item,$grade));
674 }
675}
676?>