|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 if (!defined('MOODLE_INTERNAL')) { 00003 die('Direct access to this script is forbidden.'); 00004 } 00005 require_once($CFG->libdir.'/completionlib.php'); 00006 00007 global $DB; 00008 Mock::generate(get_class($DB), 'mock_database'); 00009 Mock::generate('moodle_transaction', 'mock_transaction'); 00010 00011 Mock::generatePartial('completion_info','completion_cutdown', 00012 array('delete_all_state','get_tracked_users','update_state', 00013 'internal_get_grade_state','is_enabled','get_data','internal_get_state','internal_set_data')); 00014 Mock::generatePartial('completion_info','completion_cutdown2', 00015 array('is_enabled','get_data','internal_get_state','internal_set_data')); 00016 Mock::generatePartial('completion_info','completion_cutdown3', 00017 array('internal_get_grade_state')); 00018 00019 class fake_recordset implements Iterator { 00020 var $closed; 00021 var $values,$index; 00022 00023 function fake_recordset($values) { 00024 $this->values=$values; 00025 $this->index=0; 00026 } 00027 00028 function current() { 00029 return $this->values[$this->index]; 00030 } 00031 00032 function key() { 00033 return $this->values[$this->index]; 00034 } 00035 00036 function next() { 00037 $this->index++; 00038 } 00039 00040 function rewind() { 00041 $this->index=0; 00042 } 00043 00044 function valid() { 00045 return count($this->values) > $this->index; 00046 } 00047 00048 function close() { 00049 $this->closed=true; 00050 } 00051 00052 function was_closed() { 00053 return $this->closed; 00054 } 00055 } 00056 00061 class TimeModifiedExpectation extends SimpleExpectation { 00062 private $otherfields; 00063 00067 function TimeModifiedExpectation($otherfields) { 00068 $this->otherfields=$otherfields; 00069 } 00070 00071 function test($thing) { 00072 $thingfields=(array)$thing; 00073 foreach($this->otherfields as $key=>$value) { 00074 if(!array_key_exists($key,$thingfields)) { 00075 return false; 00076 } 00077 if($thingfields[$key]!=$value) { 00078 return false; 00079 } 00080 } 00081 00082 $timedifference=time()-$thing->timemodified; 00083 return ($timedifference < 2 && $timedifference>=0); 00084 } 00085 00086 function testMessage($thing) { 00087 return "Object does not match fields/time requirement"; 00088 } 00089 } 00090 00091 class completionlib_test extends UnitTestCaseUsingDatabase { 00092 00093 public static $includecoverage = array('lib/completionlib.php'); 00094 var $realdb,$realcfg,$realsession,$realuser; 00095 00096 function setUp() { 00097 global $DB,$CFG,$SESSION,$USER; 00098 $this->realdb=$DB; 00099 $this->realcfg=$CFG; 00100 $this->realsession=$SESSION; 00101 $this->prevuser=$USER; 00102 $DB=new mock_database(); 00103 $CFG=clone($this->realcfg); 00104 $CFG->prefix='test_'; 00105 $CFG->enablecompletion=COMPLETION_ENABLED; 00106 $SESSION=new stdClass(); 00107 $USER=(object)array('id'=>314159); 00108 } 00109 00110 function tearDown() { 00111 global $DB,$CFG,$SESSION,$USER; 00112 $DB=$this->realdb; 00113 $CFG=$this->realcfg; 00114 $SESSION=$this->realsession; 00115 $USER=$this->prevuser; 00116 } 00117 00118 function test_is_enabled() { 00119 global $CFG; 00120 00121 // Config alone 00122 $CFG->enablecompletion=COMPLETION_DISABLED; 00123 $this->assertEqual(COMPLETION_DISABLED,completion_info::is_enabled_for_site()); 00124 $CFG->enablecompletion=COMPLETION_ENABLED; 00125 $this->assertEqual(COMPLETION_ENABLED,completion_info::is_enabled_for_site()); 00126 00127 // Course 00128 //$course=new stdClass; 00129 $course=(object)array('id'=>13); 00130 $c=new completion_info($course); 00131 $course->enablecompletion=COMPLETION_DISABLED; 00132 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled()); 00133 $course->enablecompletion=COMPLETION_ENABLED; 00134 $this->assertEqual(COMPLETION_ENABLED,$c->is_enabled()); 00135 $CFG->enablecompletion=COMPLETION_DISABLED; 00136 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled()); 00137 00138 // Course and CM 00139 $cm=new stdClass; 00140 $cm->completion=COMPLETION_TRACKING_MANUAL; 00141 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm)); 00142 $CFG->enablecompletion=COMPLETION_ENABLED; 00143 $course->enablecompletion=COMPLETION_DISABLED; 00144 $this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm)); 00145 $course->enablecompletion=COMPLETION_ENABLED; 00146 $this->assertEqual(COMPLETION_TRACKING_MANUAL,$c->is_enabled($cm)); 00147 $cm->completion=COMPLETION_TRACKING_NONE; 00148 $this->assertEqual(COMPLETION_TRACKING_NONE,$c->is_enabled($cm)); 00149 $cm->completion=COMPLETION_TRACKING_AUTOMATIC; 00150 $this->assertEqual(COMPLETION_TRACKING_AUTOMATIC,$c->is_enabled($cm)); 00151 } 00152 00153 function test_update_state() { 00154 $c=new completion_cutdown2(); 00155 $c->__construct((object)array('id'=>42)); 00156 $cm=(object)array('id'=>13,'course'=>42); 00157 00158 // Not enabled, should do nothing 00159 $c->expectAt(0,'is_enabled',array($cm)); 00160 $c->setReturnValueAt(0,'is_enabled',false); 00161 $c->update_state($cm); 00162 00163 // Enabled, but current state is same as possible result, do nothing 00164 $current=(object)array('completionstate'=>COMPLETION_COMPLETE); 00165 $c->expectAt(1,'is_enabled',array($cm)); 00166 $c->setReturnValueAt(1,'is_enabled',true); 00167 00168 $c->expectAt(0,'get_data',array($cm,false,0)); 00169 $c->setReturnValueAt(0,'get_data',$current); 00170 $c->update_state($cm,COMPLETION_COMPLETE); 00171 00172 // Enabled, but current state is a specific one and new state is just 00173 // omplete, so do nothing 00174 $current->completionstate=COMPLETION_COMPLETE_PASS; 00175 $c->expectAt(2,'is_enabled',array($cm)); 00176 $c->setReturnValueAt(2,'is_enabled',true); 00177 $c->expectAt(1,'get_data',array($cm,false,0)); 00178 $c->setReturnValueAt(1,'get_data',$current); 00179 $c->update_state($cm,COMPLETION_COMPLETE); 00180 00181 // Manual, change state (no change) 00182 $cm->completion=COMPLETION_TRACKING_MANUAL; 00183 $current->completionstate=COMPLETION_COMPLETE; 00184 $c->expectAt(3,'is_enabled',array($cm)); 00185 $c->setReturnValueAt(3,'is_enabled',true); 00186 $c->expectAt(2,'get_data',array($cm,false,0)); 00187 $c->setReturnValueAt(2,'get_data',$current); 00188 $c->update_state($cm,COMPLETION_COMPLETE); 00189 00190 // Manual, change state (change) 00191 $c->expectAt(4,'is_enabled',array($cm)); 00192 $c->setReturnValueAt(4,'is_enabled',true); 00193 $c->expectAt(3,'get_data',array($cm,false,0)); 00194 $c->setReturnValueAt(3,'get_data',$current); 00195 $c->expectAt(0,'internal_set_data',array($cm, 00196 new TimeModifiedExpectation(array('completionstate'=>COMPLETION_INCOMPLETE)))); 00197 $c->update_state($cm,COMPLETION_INCOMPLETE); 00198 00199 // Auto, change state 00200 $cm->completion=COMPLETION_TRACKING_AUTOMATIC; 00201 $c->expectAt(5,'is_enabled',array($cm)); 00202 $c->setReturnValueAt(5,'is_enabled',true); 00203 $c->expectAt(4,'get_data',array($cm,false,0)); 00204 $c->setReturnValueAt(4,'get_data',$current); 00205 $c->expectAt(0,'internal_get_state',array($cm,0,$current)); 00206 $c->setReturnValueAt(0,'internal_get_state',COMPLETION_COMPLETE_PASS); 00207 $c->expectAt(1,'internal_set_data',array($cm, 00208 new TimeModifiedExpectation(array('completionstate'=>COMPLETION_COMPLETE_PASS)))); 00209 $c->update_state($cm,COMPLETION_COMPLETE_PASS); 00210 00211 $c->tally(); 00212 } 00213 00214 function test_internal_get_state() { 00215 global $DB; 00216 00217 $c=new completion_cutdown3(); 00218 $c->__construct((object)array('id'=>42)); 00219 $cm=(object)array('id'=>13,'course'=>42,'completiongradeitemnumber'=>null); 00220 00221 // If view is required, but they haven't viewed it yet 00222 $cm->completionview=COMPLETION_VIEW_REQUIRED; 00223 $current=(object)array('viewed'=>COMPLETION_NOT_VIEWED); 00224 $this->assertEqual(COMPLETION_INCOMPLETE,$c->internal_get_state($cm,123,$current)); 00225 00226 // OK set view not required 00227 $cm->completionview=COMPLETION_VIEW_NOT_REQUIRED; 00228 00229 // Test not getting module name 00230 $cm->modname='label'; 00231 $this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current)); 00232 00233 // Test getting module name 00234 $cm->module=13; 00235 unset($cm->modname); 00236 $DB->expectOnce('get_field',array('modules','name',array('id'=>13))); 00237 $DB->setReturnValue('get_field','label'); 00238 $this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current)); 00239 00240 // Note: This function is not fully tested (including kind of the main 00241 // part) because: 00242 // * the grade_item/grade_grade calls are static and can't be mocked 00243 // * the plugin_supports call is static and can't be mocked 00244 00245 $DB->tally(); 00246 $c->tally(); 00247 } 00248 00249 function test_set_module_viewed() { 00250 $c=new completion_cutdown(); 00251 $c->__construct((object)array('id'=>42)); 00252 $cm=(object)array('id'=>13,'course'=>42); 00253 00254 // Not tracking completion, should do nothing 00255 $cm->completionview=COMPLETION_VIEW_NOT_REQUIRED; 00256 $c->set_module_viewed($cm); 00257 00258 // Tracking completion but completion is disabled, should do nothing 00259 $cm->completionview=COMPLETION_VIEW_REQUIRED; 00260 $c->expectAt(0,'is_enabled',array($cm)); 00261 $c->setReturnValueAt(0,'is_enabled',false); 00262 $c->set_module_viewed($cm); 00263 00264 // Now it's enabled, we expect it to get data. If data already has 00265 // viewed, still do nothing 00266 $c->expectAt(1,'is_enabled',array($cm)); 00267 $c->setReturnValueAt(1,'is_enabled',true); 00268 $c->expectAt(0,'get_data',array($cm,0)); 00269 $hasviewed=(object)array('viewed'=>COMPLETION_VIEWED); 00270 $c->setReturnValueAt(0,'get_data',$hasviewed); 00271 $c->set_module_viewed($cm); 00272 00273 // OK finally one that hasn't been viewed, now it should set it viewed 00274 // and update state 00275 $c->expectAt(2,'is_enabled',array($cm)); 00276 $c->setReturnValueAt(2,'is_enabled',true); 00277 $notviewed=(object)array('viewed'=>COMPLETION_NOT_VIEWED); 00278 $c->expectAt(1,'get_data',array($cm,1337)); 00279 $c->setReturnValueAt(1,'get_data',$notviewed); 00280 $c->expectOnce('internal_set_data',array($cm,$hasviewed)); 00281 $c->expectOnce('update_state',array($cm,COMPLETION_COMPLETE,1337)); 00282 $c->set_module_viewed($cm,1337); 00283 00284 $c->tally(); 00285 } 00286 00287 function test_count_user_data() { 00288 global $DB; 00289 $course=(object)array('id'=>13); 00290 $cm=(object)array('id'=>42); 00291 $DB->setReturnValue('get_field_sql',666); 00292 $DB->expectOnce('get_field_sql',array(new IgnoreWhitespaceExpectation("SELECT 00293 COUNT(1) 00294 FROM 00295 {course_modules_completion} 00296 WHERE 00297 coursemoduleid=? AND completionstate<>0"),array(42))); 00298 $c=new completion_info($course); 00299 $this->assertEqual(666,$c->count_user_data($cm)); 00300 00301 $DB->tally(); 00302 } 00303 00304 function test_delete_all_state() { 00305 global $DB,$SESSION; 00306 $course=(object)array('id'=>13); 00307 $cm=(object)array('id'=>42,'course'=>13); 00308 $c=new completion_info($course); 00309 // Check it works ok without data in session 00310 $DB->expectAt(0,'delete_records', 00311 array('course_modules_completion',array('coursemoduleid'=>42))); 00312 $c->delete_all_state($cm); 00313 00314 // Build up a session to check it deletes the right bits from it 00315 // (and not other bits) 00316 $SESSION->completioncache=array(); 00317 $SESSION->completioncache[13]=array(); 00318 $SESSION->completioncache[13][42]='foo'; 00319 $SESSION->completioncache[13][43]='foo'; 00320 $SESSION->completioncache[14]=array(); 00321 $SESSION->completioncache[14][42]='foo'; 00322 $DB->expectAt(1,'delete_records', 00323 array('course_modules_completion',array('coursemoduleid'=>42))); 00324 $c->delete_all_state($cm); 00325 $this->assertEqual(array(13=>array(43=>'foo'),14=>array(42=>'foo')), 00326 $SESSION->completioncache); 00327 00328 $DB->tally(); 00329 } 00330 00331 function test_reset_all_state() { 00332 global $DB; 00333 $c=new completion_cutdown(); 00334 $c->__construct((object)array('id'=>42)); 00335 00336 $cm=(object)array('id'=>13,'course'=>42, 00337 'completion'=>COMPLETION_TRACKING_AUTOMATIC); 00338 00339 $DB->setReturnValue('get_recordset',new fake_recordset(array( 00340 (object)array('id'=>1,'userid'=>100), 00341 (object)array('id'=>2,'userid'=>101), 00342 ))); 00343 $DB->expectOnce('get_recordset',array('course_modules_completion', 00344 array('coursemoduleid'=>13),'','userid')); 00345 $c->expectOnce('delete_all_state',array($cm)); 00346 $c->expectOnce('get_tracked_users',array()); 00347 $c->setReturnValue('get_tracked_users',array( 00348 (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'), 00349 (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'), 00350 )); 00351 00352 $c->expectAt(0,'update_state',array($cm,COMPLETION_UNKNOWN,100)); 00353 $c->expectAt(1,'update_state',array($cm,COMPLETION_UNKNOWN,101)); 00354 $c->expectAt(2,'update_state',array($cm,COMPLETION_UNKNOWN,201)); 00355 00356 $c->reset_all_state($cm); 00357 00358 $DB->tally(); 00359 $c->tally(); 00360 } 00361 00362 function test_get_data() { 00363 global $DB,$SESSION; 00364 00365 $c=new completion_info((object)array('id'=>42)); 00366 $cm=(object)array('id'=>13,'course'=>42); 00367 00368 // 1. Not current user, record exists 00369 $sillyrecord=(object)array('frog'=>'kermit'); 00370 $DB->expectAt(0,'get_record',array('course_modules_completion', 00371 array('coursemoduleid'=>13,'userid'=>123))); 00372 $DB->setReturnValueAt(0,'get_record',$sillyrecord); 00373 $result=$c->get_data($cm,false,123); 00374 $this->assertEqual($sillyrecord,$result); 00375 $this->assertTrue(empty($SESSION->completioncache)); 00376 00377 // 2. Not current user, default record, wholecourse (ignored) 00378 $DB->expectAt(1,'get_record',array('course_modules_completion', 00379 array('coursemoduleid'=>13,'userid'=>123))); 00380 $DB->setReturnValueAt(1,'get_record',false); 00381 $result=$c->get_data($cm,true,123); 00382 $this->assertEqual((object)array( 00383 'id'=>'0','coursemoduleid'=>13,'userid'=>123,'completionstate'=>0, 00384 'viewed'=>0,'timemodified'=>0),$result); 00385 $this->assertTrue(empty($SESSION->completioncache)); 00386 00387 // 3. Current user, single record, not from cache 00388 $DB->expectAt(2,'get_record',array('course_modules_completion', 00389 array('coursemoduleid'=>13,'userid'=>314159))); 00390 $DB->setReturnValueAt(2,'get_record',$sillyrecord); 00391 $result=$c->get_data($cm); 00392 $this->assertEqual($sillyrecord,$result); 00393 $this->assertEqual($sillyrecord,$SESSION->completioncache[42][13]); 00394 // When checking time(), allow for second overlaps 00395 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2); 00396 00397 // 4. Current user, 'whole course', but from cache 00398 $result=$c->get_data($cm,true); 00399 $this->assertEqual($sillyrecord,$result); 00400 00401 // 5. Current user, single record, cache expired 00402 $SESSION->completioncache[42]['updated']=37; // Quite a long time ago 00403 $now=time(); 00404 $SESSION->completioncache[17]['updated']=$now; 00405 $SESSION->completioncache[39]['updated']=72; // Also a long time ago 00406 $DB->expectAt(3,'get_record',array('course_modules_completion', 00407 array('coursemoduleid'=>13,'userid'=>314159))); 00408 $DB->setReturnValueAt(3,'get_record',$sillyrecord); 00409 $result=$c->get_data($cm,false); 00410 $this->assertEqual($sillyrecord,$result); 00411 // Check that updated value is right, then fudge it to make next compare 00412 // work 00413 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2); 00414 $SESSION->completioncache[42]['updated']=$now; 00415 // Check things got expired from cache 00416 $this->assertEqual(array(42=>array(13=>$sillyrecord,'updated'=>$now), 00417 17=>array('updated'=>$now)),$SESSION->completioncache); 00418 00419 // 6. Current user, 'whole course' and record not in cache 00420 unset($SESSION->completioncache); 00421 00422 // Scenario: Completion data exists for one CMid 00423 $basicrecord=(object)array('coursemoduleid'=>13); 00424 $DB->setReturnValueAt(0,'get_records_sql',array( 00425 1=>$basicrecord 00426 )); 00427 $DB->expectAt(0,'get_records_sql',array(new IgnoreWhitespaceExpectation(" 00428 SELECT 00429 cmc.* 00430 FROM 00431 {course_modules} cm 00432 INNER JOIN {course_modules_completion} cmc ON cmc.coursemoduleid=cm.id 00433 WHERE 00434 cm.course=? AND cmc.userid=?"),array(42,314159))); 00435 00436 // There are two CMids in total, the one we had data for and another one 00437 $modinfo->cms=array((object)array('id'=>13),(object)array('id'=>14)); 00438 $result=$c->get_data($cm,true,0,$modinfo); 00439 00440 // Check result 00441 $this->assertEqual($basicrecord,$result); 00442 00443 // Check the cache contents 00444 $this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2); 00445 $SESSION->completioncache[42]['updated']=$now; 00446 $this->assertEqual(array(42=>array(13=>$basicrecord,14=>(object)array( 00447 'id'=>'0','coursemoduleid'=>14,'userid'=>314159,'completionstate'=>0, 00448 'viewed'=>0,'timemodified'=>0),'updated'=>$now)),$SESSION->completioncache); 00449 00450 $DB->tally(); 00451 } 00452 00453 function test_internal_set_data() { 00454 global $DB,$SESSION; 00455 00456 $cm = (object)array('course' => 42,'id' => 13); 00457 $c = new completion_info((object)array('id' => 42)); 00458 00459 // 1) Test with new data 00460 $data = (object)array('id'=>0, 'userid' => 314159, 'coursemoduleid' => 99); 00461 $DB->setReturnValueAt(0, 'start_delegated_transaction', new mock_transaction()); 00462 $DB->setReturnValueAt(0, 'insert_record', 4); 00463 $DB->expectAt(0, 'get_field', array('course_modules_completion', 'id', 00464 array('coursemoduleid' => 99, 'userid' => 314159))); 00465 $DB->expectAt(0, 'insert_record', array('course_modules_completion', $data)); 00466 $c->internal_set_data($cm, $data); 00467 $this->assertEqual(4, $data->id); 00468 $this->assertEqual(array(42 => array(13 => $data)), $SESSION->completioncache); 00469 00470 // 2) Test with existing data and for different user (not cached) 00471 unset($SESSION->completioncache); 00472 $d2 = (object)array('id' => 7, 'userid' => 17, 'coursemoduleid' => 66); 00473 $DB->setReturnValueAt(1, 'start_delegated_transaction', new mock_transaction()); 00474 $DB->expectAt(0,'update_record', array('course_modules_completion', $d2)); 00475 $c->internal_set_data($cm, $d2); 00476 $this->assertFalse(isset($SESSION->completioncache)); 00477 00478 // 3) Test where it THINKS the data is new (from cache) but actually 00479 // in the database it has been set since 00480 // 1) Test with new data 00481 $data = (object)array('id'=>0, 'userid' => 314159, 'coursemoduleid' => 99); 00482 $DB->setReturnValueAt(2, 'start_delegated_transaction', new mock_transaction()); 00483 $DB->setReturnValueAt(1, 'get_field', 13); 00484 $DB->expectAt(1, 'get_field', array('course_modules_completion', 'id', 00485 array('coursemoduleid' => 99, 'userid' => 314159))); 00486 $d3 = (object)array('id' => 13, 'userid' => 314159, 'coursemoduleid' => 99); 00487 $DB->expectAt(1,'update_record', array('course_modules_completion', $d3)); 00488 $c->internal_set_data($cm, $data); 00489 00490 $DB->tally(); 00491 } 00492 00493 function test_get_activities() { 00494 global $DB; 00495 00496 $c=new completion_info((object)array('id'=>42)); 00497 00498 // Try with no activities 00499 $DB->expectAt(0,'get_records_select',array('course_modules', 00500 'course=42 AND completion<>'.COMPLETION_TRACKING_NONE)); 00501 $DB->setReturnValueAt(0,'get_records_select',array()); 00502 $result=$c->get_activities(); 00503 $this->assertEqual(array(),$result); 00504 00505 // Try with an activity (need to fake up modinfo for it as well) 00506 $DB->expectAt(1,'get_records_select',array('course_modules', 00507 'course=42 AND completion<>'.COMPLETION_TRACKING_NONE)); 00508 $DB->setReturnValueAt(1,'get_records_select',array( 00509 13=>(object)array('id'=>13) 00510 )); 00511 $modinfo=new stdClass; 00512 $modinfo->sections=array(array(1,2,3),array(12,13,14)); 00513 $modinfo->cms[13]=(object)array('modname'=>'frog','name'=>'kermit'); 00514 $result=$c->get_activities($modinfo); 00515 $this->assertEqual(array(13=>(object)array('id'=>13,'modname'=>'frog','name'=>'kermit')),$result); 00516 00517 $DB->tally(); 00518 } 00519 00520 // get_tracked_users() cannot easily be tested because it uses 00521 // get_role_users, so skipping that 00522 00523 function test_get_progress_all() { 00524 global $DB; 00525 00526 $c=new completion_cutdown(); 00527 $c->__construct((object)array('id'=>42)); 00528 00529 // 1) Basic usage 00530 $c->expectAt(0,'get_tracked_users',array(false, array(), 0, '', '', '', null)); 00531 $c->setReturnValueAt(0,'get_tracked_users',array( 00532 (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'), 00533 (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'), 00534 )); 00535 $DB->expectAt(0,'get_in_or_equal',array(array(100,201))); 00536 $DB->setReturnValueAt(0,'get_in_or_equal',array(' IN (100,201)',array())); 00537 $DB->expectAt(0,'get_recordset_sql',array(new IgnoreWhitespaceExpectation(" 00538 SELECT 00539 cmc.* 00540 FROM 00541 {course_modules} cm 00542 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid 00543 WHERE 00544 cm.course=? AND cmc.userid IN (100,201)"),array(42))); 00545 $progress1=(object)array('userid'=>100,'coursemoduleid'=>13); 00546 $progress2=(object)array('userid'=>201,'coursemoduleid'=>14); 00547 $DB->setReturnValueAt(0,'get_recordset_sql',new fake_recordset(array( 00548 $progress1,$progress2 00549 ))); 00550 $this->assertEqual(array( 00551 00552 100 => (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh', 00553 'progress'=>array(13=>$progress1)), 00554 201 => (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy', 00555 'progress'=>array(14=>$progress2)), 00556 ),$c->get_progress_all(false)); 00557 00558 // 2) With more than 1,000 results 00559 $c->expectAt(1,'get_tracked_users',array(true, 3, 0, '', '', '', null)); 00560 00561 $tracked=array(); 00562 $ids=array(); 00563 $progress=array(); 00564 for($i=100;$i<2000;$i++) { 00565 $tracked[]=(object)array('id'=>$i,'firstname'=>'frog','lastname'=>$i); 00566 $ids[]=$i; 00567 $progress[]=(object)array('userid'=>$i,'coursemoduleid'=>13); 00568 $progress[]=(object)array('userid'=>$i,'coursemoduleid'=>14); 00569 } 00570 $c->setReturnValueAt(1,'get_tracked_users',$tracked); 00571 00572 $DB->expectAt(1,'get_in_or_equal',array(array_slice($ids,0,1000))); 00573 $DB->setReturnValueAt(1,'get_in_or_equal',array(' IN whatever',array())); 00574 $DB->expectAt(1,'get_recordset_sql',array(new IgnoreWhitespaceExpectation(" 00575 SELECT 00576 cmc.* 00577 FROM 00578 {course_modules} cm 00579 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid 00580 WHERE 00581 cm.course=? AND cmc.userid IN whatever"),array(42))); 00582 $DB->setReturnValueAt(1,'get_recordset_sql',new fake_recordset(array_slice($progress,0,1000))); 00583 $DB->expectAt(2,'get_in_or_equal',array(array_slice($ids,1000))); 00584 $DB->setReturnValueAt(2,'get_in_or_equal',array(' IN whatever2',array())); 00585 $DB->expectAt(2,'get_recordset_sql',array(new IgnoreWhitespaceExpectation(" 00586 SELECT 00587 cmc.* 00588 FROM 00589 {course_modules} cm 00590 INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid 00591 WHERE 00592 cm.course=? AND cmc.userid IN whatever2"),array(42))); 00593 $DB->setReturnValueAt(2,'get_recordset_sql',new fake_recordset(array_slice($progress,1000))); 00594 $result=$c->get_progress_all(true,3); 00595 $resultok=true; 00596 $resultok = $resultok && ($ids==array_keys($result)); 00597 00598 foreach($result as $userid => $data) { 00599 $resultok = $resultok && $data->firstname=='frog'; 00600 $resultok = $resultok && $data->lastname==$userid; 00601 $resultok = $resultok && $data->id==$userid; 00602 $cms=$data->progress; 00603 $resultok= $resultok && (array(13,14)==array_keys($cms)); 00604 $resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>13)==$cms[13]); 00605 $resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>14)==$cms[14]); 00606 } 00607 $this->assertTrue($resultok); 00608 00609 $DB->tally(); 00610 $c->tally(); 00611 } 00612 00613 function test_inform_grade_changed() { 00614 $c=new completion_cutdown(); 00615 $c->__construct((object)array('id'=>42)); 00616 00617 $cm=(object)array('course'=>42,'id'=>13,'completion'=>0,'completiongradeitemnumber'=>null); 00618 $item=(object)array('itemnumber'=>3); 00619 $grade=(object)array('userid'=>31337); 00620 00621 // Not enabled (should do nothing) 00622 $c->setReturnValueAt(0,'is_enabled',false); 00623 $c->expectAt(0,'is_enabled',array($cm)); 00624 $c->inform_grade_changed($cm,$item,$grade,false); 00625 00626 // Enabled but still no grade completion required, should still do nothing 00627 $c->setReturnValueAt(1,'is_enabled',true); 00628 $c->expectAt(1,'is_enabled',array($cm)); 00629 $c->inform_grade_changed($cm,$item,$grade,false); 00630 00631 // Enabled and completion required but item number is wrong, does nothing 00632 $cm->completiongradeitemnumber=7; 00633 $c->setReturnValueAt(2,'is_enabled',true); 00634 $c->expectAt(2,'is_enabled',array($cm)); 00635 $c->inform_grade_changed($cm,$item,$grade,false); 00636 00637 // Enabled and completion required and item number right. It is supposed 00638 // to call update_state with the new potential state being obtained from 00639 // internal_get_grade_state. 00640 $cm->completiongradeitemnumber=3; 00641 $c->setReturnValueAt(3,'is_enabled',true); 00642 $c->expectAt(3,'is_enabled',array($cm)); 00643 $c->expectAt(0,'internal_get_grade_state',array($item,$grade)); 00644 $c->setReturnValueAt(0,'internal_get_grade_state',COMPLETION_COMPLETE_PASS); 00645 $c->expectAt(0,'update_state',array($cm,COMPLETION_COMPLETE_PASS,31337)); 00646 $c->inform_grade_changed($cm,$item,$grade,false); 00647 00648 // Same as above but marked deleted. It is supposed to call update_state 00649 // with new potential state being COMPLETION_INCOMPLETE 00650 $c->setReturnValueAt(4,'is_enabled',false); 00651 $c->expectAt(4,'is_enabled',array($cm)); 00652 $c->expectAt(1,'update_state',array($cm,COMPLETION_INCOMPLETE,31337)); 00653 $c->inform_grade_changed($cm,$item,$grade,false); 00654 00655 $c->tally(); 00656 } 00657 00658 function test_internal_get_grade_state() { 00659 $item=new stdClass; 00660 $grade=new stdClass; 00661 00662 $item->gradepass=4; 00663 $item->hidden=0; 00664 $grade->rawgrade=4.0; 00665 $grade->finalgrade=null; 00666 00667 // Grade has pass mark and is not hidden, user passes 00668 $this->assertEqual( 00669 COMPLETION_COMPLETE_PASS, 00670 completion_info::internal_get_grade_state($item,$grade)); 00671 00672 // Same but user fails 00673 $grade->rawgrade=3.9; 00674 $this->assertEqual( 00675 COMPLETION_COMPLETE_FAIL, 00676 completion_info::internal_get_grade_state($item,$grade)); 00677 00678 // User fails on raw grade but passes on final 00679 $grade->finalgrade=4.0; 00680 $this->assertEqual( 00681 COMPLETION_COMPLETE_PASS, 00682 completion_info::internal_get_grade_state($item,$grade)); 00683 00684 // Item is hidden 00685 $item->hidden=1; 00686 $this->assertEqual( 00687 COMPLETION_COMPLETE, 00688 completion_info::internal_get_grade_state($item,$grade)); 00689 00690 // Item isn't hidden but has no pass mark 00691 $item->hidden=0; 00692 $item->gradepass=0; 00693 $this->assertEqual( 00694 COMPLETION_COMPLETE, 00695 completion_info::internal_get_grade_state($item,$grade)); 00696 } 00697 } 00698