moodle/lib/simpletest/testcompletionlib.php
2010-03-21 19:44:57 +00:00

683 lines
26 KiB
PHP

<?php
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.');
}
require_once($CFG->libdir.'/completionlib.php');
global $DB;
Mock::generate(get_class($DB), 'mock_database');
Mock::generatePartial('completion_info','completion_cutdown',
array('delete_all_state','internal_get_tracked_users','update_state',
'internal_get_grade_state','is_enabled','get_data','internal_get_state','internal_set_data'));
Mock::generatePartial('completion_info','completion_cutdown2',
array('is_enabled','get_data','internal_get_state','internal_set_data'));
Mock::generatePartial('completion_info','completion_cutdown3',
array('internal_get_grade_state'));
class fake_recordset implements Iterator {
var $closed;
var $values,$index;
function fake_recordset($values) {
$this->values=$values;
$this->index=0;
}
function current() {
return $this->values[$this->index];
}
function key() {
return $this->values[$this->index];
}
function next() {
$this->index++;
}
function rewind() {
$this->index=0;
}
function valid() {
return count($this->values) > $this->index;
}
function close() {
$closed=true;
}
function was_closed() {
return $closed;
}
}
/**
* Expectation that checks an object for given values (normal equality test)
* plus a 'timemodified' field that is current (last second or two).
*/
class TimeModifiedExpectation extends SimpleExpectation {
private $otherfields;
/**
* @param array $otherfields Array key=>value of required object fields
*/
function TimeModifiedExpectation($otherfields) {
$this->otherfields=$otherfields;
}
function test($thing) {
$thingfields=(array)$thing;
foreach($this->otherfields as $key=>$value) {
if(!array_key_exists($key,$thingfields)) {
return false;
}
if($thingfields[$key]!=$value) {
return false;
}
}
$timedifference=time()-$thing->timemodified;
return ($timedifference < 2 && $timedifference>=0);
}
function testMessage($thing) {
return "Object does not match fields/time requirement";
}
}
class completionlib_test extends UnitTestCase {
public static $includecoverage = array('lib/completionlib.php');
var $realdb,$realcfg,$realsession,$realuser;
function setUp() {
global $DB,$CFG,$SESSION,$USER;
$this->realdb=$DB;
$this->realcfg=$CFG;
$this->realsession=$SESSION;
$this->prevuser=$USER;
$DB=new mock_database();
$CFG=clone($this->realcfg);
$CFG->prefix='test_';
$CFG->enablecompletion=COMPLETION_ENABLED;
$SESSION=new stdClass();
$USER=(object)array('id'=>314159);
}
function tearDown() {
global $DB,$CFG,$SESSION,$USER;
$DB=$this->realdb;
$CFG=$this->realcfg;
$SESSION=$this->realsession;
$USER=$this->prevuser;
}
function test_is_enabled() {
global $CFG;
// Config alone
$CFG->enablecompletion=COMPLETION_DISABLED;
$this->assertEqual(COMPLETION_DISABLED,completion_info::is_enabled_for_site());
$CFG->enablecompletion=COMPLETION_ENABLED;
$this->assertEqual(COMPLETION_ENABLED,completion_info::is_enabled_for_site());
// Course
$course=new stdClass;
$c=new completion_info($course);
$course->enablecompletion=COMPLETION_DISABLED;
$this->assertEqual(COMPLETION_DISABLED,$c->is_enabled());
$course->enablecompletion=COMPLETION_ENABLED;
$this->assertEqual(COMPLETION_ENABLED,$c->is_enabled());
$CFG->enablecompletion=COMPLETION_DISABLED;
$this->assertEqual(COMPLETION_DISABLED,$c->is_enabled());
// Course and CM
$cm=new stdClass;
$cm->completion=COMPLETION_TRACKING_MANUAL;
$this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm));
$CFG->enablecompletion=COMPLETION_ENABLED;
$course->enablecompletion=COMPLETION_DISABLED;
$this->assertEqual(COMPLETION_DISABLED,$c->is_enabled($cm));
$course->enablecompletion=COMPLETION_ENABLED;
$this->assertEqual(COMPLETION_TRACKING_MANUAL,$c->is_enabled($cm));
$cm->completion=COMPLETION_TRACKING_NONE;
$this->assertEqual(COMPLETION_TRACKING_NONE,$c->is_enabled($cm));
$cm->completion=COMPLETION_TRACKING_AUTOMATIC;
$this->assertEqual(COMPLETION_TRACKING_AUTOMATIC,$c->is_enabled($cm));
}
function test_update_state() {
$c=new completion_cutdown2();
$c->__construct((object)array('id'=>42));
$cm=(object)array('id'=>13,'course'=>42);
// Not enabled, should do nothing
$c->expectAt(0,'is_enabled',array($cm));
$c->setReturnValueAt(0,'is_enabled',false);
$c->update_state($cm);
// Enabled, but current state is same as possible result, do nothing
$current=(object)array('completionstate'=>COMPLETION_COMPLETE);
$c->expectAt(1,'is_enabled',array($cm));
$c->setReturnValueAt(1,'is_enabled',true);
$c->expectAt(0,'get_data',array($cm,false,0));
$c->setReturnValueAt(0,'get_data',$current);
$c->update_state($cm,COMPLETION_COMPLETE);
// Enabled, but current state is a specific one and new state is just
// omplete, so do nothing
$current->completionstate=COMPLETION_COMPLETE_PASS;
$c->expectAt(2,'is_enabled',array($cm));
$c->setReturnValueAt(2,'is_enabled',true);
$c->expectAt(1,'get_data',array($cm,false,0));
$c->setReturnValueAt(1,'get_data',$current);
$c->update_state($cm,COMPLETION_COMPLETE);
// Manual, change state (no change)
$cm->completion=COMPLETION_TRACKING_MANUAL;
$current->completionstate=COMPLETION_COMPLETE;
$c->expectAt(3,'is_enabled',array($cm));
$c->setReturnValueAt(3,'is_enabled',true);
$c->expectAt(2,'get_data',array($cm,false,0));
$c->setReturnValueAt(2,'get_data',$current);
$c->update_state($cm,COMPLETION_COMPLETE);
// Manual, change state (change)
$c->expectAt(4,'is_enabled',array($cm));
$c->setReturnValueAt(4,'is_enabled',true);
$c->expectAt(3,'get_data',array($cm,false,0));
$c->setReturnValueAt(3,'get_data',$current);
$c->expectAt(0,'internal_set_data',array($cm,
new TimeModifiedExpectation(array('completionstate'=>COMPLETION_INCOMPLETE))));
$c->update_state($cm,COMPLETION_INCOMPLETE);
// Auto, change state
$cm->completion=COMPLETION_TRACKING_AUTOMATIC;
$c->expectAt(5,'is_enabled',array($cm));
$c->setReturnValueAt(5,'is_enabled',true);
$c->expectAt(4,'get_data',array($cm,false,0));
$c->setReturnValueAt(4,'get_data',$current);
$c->expectAt(0,'internal_get_state',array($cm,0,$current));
$c->setReturnValueAt(0,'internal_get_state',COMPLETION_COMPLETE_PASS);
$c->expectAt(1,'internal_set_data',array($cm,
new TimeModifiedExpectation(array('completionstate'=>COMPLETION_COMPLETE_PASS))));
$c->update_state($cm,COMPLETION_COMPLETE_PASS);
$c->tally();
}
function test_internal_get_state() {
global $DB;
$c=new completion_cutdown3();
$c->__construct((object)array('id'=>42));
$cm=(object)array('id'=>13,'course'=>42,'completiongradeitemnumber'=>null);
// If view is required, but they haven't viewed it yet
$cm->completionview=COMPLETION_VIEW_REQUIRED;
$current=(object)array('viewed'=>COMPLETION_NOT_VIEWED);
$this->assertEqual(COMPLETION_INCOMPLETE,$c->internal_get_state($cm,123,$current));
// OK set view not required
$cm->completionview=COMPLETION_VIEW_NOT_REQUIRED;
// Test not getting module name
$cm->modname='label';
$this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current));
// Test getting module name
$cm->module=13;
unset($cm->modname);
$DB->expectOnce('get_field',array('modules','name',array('id'=>13)));
$DB->setReturnValue('get_field','label');
$this->assertEqual(COMPLETION_COMPLETE,$c->internal_get_state($cm,123,$current));
// Note: This function is not fully tested (including kind of the main
// part) because:
// * the grade_item/grade_grade calls are static and can't be mocked
// * the plugin_supports call is static and can't be mocked
$DB->tally();
$c->tally();
}
function test_set_module_viewed() {
$c=new completion_cutdown();
$c->__construct((object)array('id'=>42));
$cm=(object)array('id'=>13,'course'=>42);
// Not tracking completion, should do nothing
$cm->completionview=COMPLETION_VIEW_NOT_REQUIRED;
$c->set_module_viewed($cm);
// Tracking completion but completion is disabled, should do nothing
$cm->completionview=COMPLETION_VIEW_REQUIRED;
$c->expectAt(0,'is_enabled',array($cm));
$c->setReturnValueAt(0,'is_enabled',false);
$c->set_module_viewed($cm);
// Now it's enabled, we expect it to get data. If data already has
// viewed, still do nothing
$c->expectAt(1,'is_enabled',array($cm));
$c->setReturnValueAt(1,'is_enabled',true);
$c->expectAt(0,'get_data',array($cm,0));
$hasviewed=(object)array('viewed'=>COMPLETION_VIEWED);
$c->setReturnValueAt(0,'get_data',$hasviewed);
$c->set_module_viewed($cm);
// OK finally one that hasn't been viewed, now it should set it viewed
// and update state
$c->expectAt(2,'is_enabled',array($cm));
$c->setReturnValueAt(2,'is_enabled',true);
$notviewed=(object)array('viewed'=>COMPLETION_NOT_VIEWED);
$c->expectAt(1,'get_data',array($cm,1337));
$c->setReturnValueAt(1,'get_data',$notviewed);
$c->expectOnce('internal_set_data',array($cm,$hasviewed));
$c->expectOnce('update_state',array($cm,COMPLETION_COMPLETE,1337));
$c->set_module_viewed($cm,1337);
$c->tally();
}
function test_count_user_data() {
global $DB;
$cm=(object)array('id'=>42);
$DB->setReturnValue('get_field_sql',666);
$DB->expectOnce('get_field_sql',array(new IgnoreWhitespaceExpectation("SELECT
COUNT(1)
FROM
{course_modules_completion}
WHERE
coursemoduleid=? AND completionstate<>0"),array(42)));
$c=new completion_info(null);
$this->assertEqual(666,$c->count_user_data($cm));
$DB->tally();
}
function test_delete_all_state() {
global $DB,$SESSION;
$course=(object)array('id'=>13);
$cm=(object)array('id'=>42,'course'=>13);
$c=new completion_info($course);
// Check it works ok without data in session
$DB->expectAt(0,'delete_records',
array('course_modules_completion',array('coursemoduleid'=>42)));
$c->delete_all_state($cm);
// Build up a session to check it deletes the right bits from it
// (and not other bits)
$SESSION->completioncache=array();
$SESSION->completioncache[13]=array();
$SESSION->completioncache[13][42]='foo';
$SESSION->completioncache[13][43]='foo';
$SESSION->completioncache[14]=array();
$SESSION->completioncache[14][42]='foo';
$DB->expectAt(1,'delete_records',
array('course_modules_completion',array('coursemoduleid'=>42)));
$c->delete_all_state($cm);
$this->assertEqual(array(13=>array(43=>'foo'),14=>array(42=>'foo')),
$SESSION->completioncache);
$DB->tally();
}
function test_reset_all_state() {
global $DB;
$c=new completion_cutdown();
$c->__construct((object)array('id'=>42));
$cm=(object)array('id'=>13,'course'=>42,
'completion'=>COMPLETION_TRACKING_AUTOMATIC);
$DB->setReturnValue('get_recordset',new fake_recordset(array(
(object)array('id'=>1,'userid'=>100),
(object)array('id'=>2,'userid'=>101),
)));
$DB->expectOnce('get_recordset',array('course_modules_completion',
array('coursemoduleid'=>13),'','userid'));
$c->expectOnce('delete_all_state',array($cm));
$c->expectOnce('internal_get_tracked_users',array(false));
$c->setReturnValue('internal_get_tracked_users',array(
(object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'),
(object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'),
));
$c->expectAt(0,'update_state',array($cm,COMPLETION_UNKNOWN,100));
$c->expectAt(1,'update_state',array($cm,COMPLETION_UNKNOWN,101));
$c->expectAt(2,'update_state',array($cm,COMPLETION_UNKNOWN,201));
$c->reset_all_state($cm);
$DB->tally();
$c->tally();
}
function test_get_data() {
global $DB,$SESSION;
$c=new completion_info((object)array('id'=>42));
$cm=(object)array('id'=>13,'course'=>42);
// 1. Not current user, record exists
$sillyrecord=(object)array('frog'=>'kermit');
$DB->expectAt(0,'get_record',array('course_modules_completion',
array('coursemoduleid'=>13,'userid'=>123)));
$DB->setReturnValueAt(0,'get_record',$sillyrecord);
$result=$c->get_data($cm,false,123);
$this->assertEqual($sillyrecord,$result);
$this->assertTrue(empty($SESSION->completioncache));
// 2. Not current user, default record, wholecourse (ignored)
$DB->expectAt(1,'get_record',array('course_modules_completion',
array('coursemoduleid'=>13,'userid'=>123)));
$DB->setReturnValueAt(1,'get_record',false);
$result=$c->get_data($cm,true,123);
$this->assertEqual((object)array(
'id'=>'0','coursemoduleid'=>13,'userid'=>123,'completionstate'=>0,
'viewed'=>0,'timemodified'=>0),$result);
$this->assertTrue(empty($SESSION->completioncache));
// 3. Current user, single record, not from cache
$DB->expectAt(2,'get_record',array('course_modules_completion',
array('coursemoduleid'=>13,'userid'=>314159)));
$DB->setReturnValueAt(2,'get_record',$sillyrecord);
$result=$c->get_data($cm);
$this->assertEqual($sillyrecord,$result);
$this->assertEqual($sillyrecord,$SESSION->completioncache[42][13]);
// When checking time(), allow for second overlaps
$this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
// 4. Current user, 'whole course', but from cache
$result=$c->get_data($cm,true);
$this->assertEqual($sillyrecord,$result);
// 5. Current user, single record, cache expired
$SESSION->completioncache[42]['updated']=37; // Quite a long time ago
$now=time();
$SESSION->completioncache[17]['updated']=$now;
$SESSION->completioncache[39]['updated']=72; // Also a long time ago
$DB->expectAt(3,'get_record',array('course_modules_completion',
array('coursemoduleid'=>13,'userid'=>314159)));
$DB->setReturnValueAt(3,'get_record',$sillyrecord);
$result=$c->get_data($cm,false);
$this->assertEqual($sillyrecord,$result);
// Check that updated value is right, then fudge it to make next compare
// work
$this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
$SESSION->completioncache[42]['updated']=$now;
// Check things got expired from cache
$this->assertEqual(array(42=>array(13=>$sillyrecord,'updated'=>$now),
17=>array('updated'=>$now)),$SESSION->completioncache);
// 6. Current user, 'whole course' and record not in cache
unset($SESSION->completioncache);
// Scenario: Completion data exists for one CMid
$basicrecord=(object)array('coursemoduleid'=>13);
$DB->setReturnValueAt(0,'get_records_sql',array(
1=>$basicrecord
));
$DB->expectAt(0,'get_records_sql',array(new IgnoreWhitespaceExpectation("
SELECT
cmc.*
FROM
{course_modules} cm
INNER JOIN {course_modules_completion} cmc ON cmc.coursemoduleid=cm.id
WHERE
cm.course=? AND cmc.userid=?"),array(42,314159)));
// There are two CMids in total, the one we had data for and another one
$modinfo->cms=array((object)array('id'=>13),(object)array('id'=>14));
$result=$c->get_data($cm,true,0,$modinfo);
// Check result
$this->assertEqual($basicrecord,$result);
// Check the cache contents
$this->assertTrue(time()-$SESSION->completioncache[42]['updated']<2);
$SESSION->completioncache[42]['updated']=$now;
$this->assertEqual(array(42=>array(13=>$basicrecord,14=>(object)array(
'id'=>'0','coursemoduleid'=>14,'userid'=>314159,'completionstate'=>0,
'viewed'=>0,'timemodified'=>0),'updated'=>$now)),$SESSION->completioncache);
$DB->tally();
}
function test_internal_set_data() {
global $DB,$SESSION;
$cm=(object)array('course'=>42,'id'=>13);
$c=new completion_info((object)array('id'=>42));
// 1) Test with new data
$data=(object)array('id'=>0,'userid'=>314159);
$DB->setReturnValueAt(0,'insert_record',4);
$DB->expectAt(0,'insert_record',array('course_modules_completion',$data));
$c->internal_set_data($cm,$data);
$this->assertEqual(4,$data->id);
$this->assertEqual(array(42=>array(13=>$data)),$SESSION->completioncache);
// 2) Test with existing data and for different user (not cached)
unset($SESSION->completioncache);
$d2=(object)array('id'=>7,'userid'=>17);
$DB->expectAt(0,'update_record',array('course_modules_completion',$d2));
$c->internal_set_data($cm,$d2);
$this->assertFalse(isset($SESSION->completioncache));
$DB->tally();
}
function test_get_activities() {
global $DB;
$c=new completion_info((object)array('id'=>42));
// Try with no activities
$DB->expectAt(0,'get_records_select',array('course_modules',
'course=42 AND completion<>'.COMPLETION_TRACKING_NONE));
$DB->setReturnValueAt(0,'get_records_select',array());
$result=$c->get_activities();
$this->assertEqual(array(),$result);
// Try with an activity (need to fake up modinfo for it as well)
$DB->expectAt(1,'get_records_select',array('course_modules',
'course=42 AND completion<>'.COMPLETION_TRACKING_NONE));
$DB->setReturnValueAt(1,'get_records_select',array(
13=>(object)array('id'=>13)
));
$modinfo=new stdClass;
$modinfo->sections=array(array(1,2,3),array(12,13,14));
$modinfo->cms[13]=(object)array('modname'=>'frog','name'=>'kermit');
$result=$c->get_activities($modinfo);
$this->assertEqual(array(13=>(object)array('id'=>13,'modname'=>'frog','name'=>'kermit')),$result);
$DB->tally();
}
// internal_get_tracked_users() cannot easily be tested because it uses
// get_role_users, so skipping that
function test_get_progress_all() {
global $DB;
$c=new completion_cutdown();
$c->__construct((object)array('id'=>42));
// 1) Basic usage
$c->expectAt(0,'internal_get_tracked_users',array(false,0));
$c->setReturnValueAt(0,'internal_get_tracked_users',array(
(object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'),
(object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'),
));
$DB->expectAt(0,'get_in_or_equal',array(array(100,201)));
$DB->setReturnValueAt(0,'get_in_or_equal',array(' IN (100,201)',array()));
$DB->expectAt(0,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
SELECT
cmc.*
FROM
{course_modules} cm
INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
WHERE
cm.course=? AND cmc.userid IN (100,201)"),array(42)));
$progress1=(object)array('userid'=>100,'coursemoduleid'=>13);
$progress2=(object)array('userid'=>201,'coursemoduleid'=>14);
$DB->setReturnValueAt(0,'get_recordset_sql',new fake_recordset(array(
$progress1,$progress2
)));
$this->assertEqual((object)array(
'start'=>0,'total'=>2,
'users'=>array(
100 => (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh',
'progress'=>array(13=>$progress1)),
201 => (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy',
'progress'=>array(14=>$progress2)),
)),$c->get_progress_all(false));
// 2) With more than 1,000 results
$c->expectAt(1,'internal_get_tracked_users',array(true,3));
$tracked=array();
$ids=array();
$progress=array();
for($i=100;$i<2000;$i++) {
$tracked[]=(object)array('id'=>$i,'firstname'=>'frog','lastname'=>$i);
$ids[]=$i;
$progress[]=(object)array('userid'=>$i,'coursemoduleid'=>13);
$progress[]=(object)array('userid'=>$i,'coursemoduleid'=>14);
}
$c->setReturnValueAt(1,'internal_get_tracked_users',$tracked);
$DB->expectAt(1,'get_in_or_equal',array(array_slice($ids,0,1000)));
$DB->setReturnValueAt(1,'get_in_or_equal',array(' IN whatever',array()));
$DB->expectAt(1,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
SELECT
cmc.*
FROM
{course_modules} cm
INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
WHERE
cm.course=? AND cmc.userid IN whatever"),array(42)));
$DB->setReturnValueAt(1,'get_recordset_sql',new fake_recordset(array_slice($progress,0,1000)));
$DB->expectAt(2,'get_in_or_equal',array(array_slice($ids,1000)));
$DB->setReturnValueAt(2,'get_in_or_equal',array(' IN whatever2',array()));
$DB->expectAt(2,'get_recordset_sql',array(new IgnoreWhitespaceExpectation("
SELECT
cmc.*
FROM
{course_modules} cm
INNER JOIN {course_modules_completion} cmc ON cm.id=cmc.coursemoduleid
WHERE
cm.course=? AND cmc.userid IN whatever2"),array(42)));
$DB->setReturnValueAt(2,'get_recordset_sql',new fake_recordset(array_slice($progress,1000)));
$result=$c->get_progress_all(true,3);
$resultok=true;
$resultok = $resultok && ($ids==array_keys($result->users));
foreach($result->users as $userid => $data) {
$resultok = $resultok && $data->firstname=='frog';
$resultok = $resultok && $data->lastname==$userid;
$resultok = $resultok && $data->id==$userid;
$cms=$data->progress;
$resultok= $resultok && (array(13,14)==array_keys($cms));
$resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>13)==$cms[13]);
$resultok= $resultok && ((object)array('userid'=>$userid,'coursemoduleid'=>14)==$cms[14]);
}
$this->assertTrue($resultok);
$DB->tally();
$c->tally();
}
function test_inform_grade_changed() {
$c=new completion_cutdown();
$c->__construct((object)array('id'=>42));
$cm=(object)array('course'=>42,'id'=>13,'completion'=>0,'completiongradeitemnumber'=>null);
$item=(object)array('itemnumber'=>3);
$grade=(object)array('userid'=>31337);
// Not enabled (should do nothing)
$c->setReturnValueAt(0,'is_enabled',false);
$c->expectAt(0,'is_enabled',array($cm));
$c->inform_grade_changed($cm,$item,$grade,false);
// Enabled but still no grade completion required, should still do nothing
$c->setReturnValueAt(1,'is_enabled',true);
$c->expectAt(1,'is_enabled',array($cm));
$c->inform_grade_changed($cm,$item,$grade,false);
// Enabled and completion required but item number is wrong, does nothing
$cm->completiongradeitemnumber=7;
$c->setReturnValueAt(2,'is_enabled',true);
$c->expectAt(2,'is_enabled',array($cm));
$c->inform_grade_changed($cm,$item,$grade,false);
// Enabled and completion required and item number right. It is supposed
// to call update_state with the new potential state being obtained from
// internal_get_grade_state.
$cm->completiongradeitemnumber=3;
$c->setReturnValueAt(3,'is_enabled',true);
$c->expectAt(3,'is_enabled',array($cm));
$c->expectAt(0,'internal_get_grade_state',array($item,$grade));
$c->setReturnValueAt(0,'internal_get_grade_state',COMPLETION_COMPLETE_PASS);
$c->expectAt(0,'update_state',array($cm,COMPLETION_COMPLETE_PASS,31337));
$c->inform_grade_changed($cm,$item,$grade,false);
// Same as above but marked deleted. It is supposed to call update_state
// with new potential state being COMPLETION_INCOMPLETE
$c->setReturnValueAt(4,'is_enabled',false);
$c->expectAt(4,'is_enabled',array($cm));
$c->expectAt(1,'update_state',array($cm,COMPLETION_INCOMPLETE,31337));
$c->inform_grade_changed($cm,$item,$grade,false);
$c->tally();
}
function test_internal_get_grade_state() {
$item=new stdClass;
$grade=new stdClass;
$item->gradepass=4;
$item->hidden=0;
$grade->rawgrade=4.0;
$grade->finalgrade=null;
// Grade has pass mark and is not hidden, user passes
$this->assertEqual(
COMPLETION_COMPLETE_PASS,
completion_info::internal_get_grade_state($item,$grade));
// Same but user fails
$grade->rawgrade=3.9;
$this->assertEqual(
COMPLETION_COMPLETE_FAIL,
completion_info::internal_get_grade_state($item,$grade));
// User fails on raw grade but passes on final
$grade->finalgrade=4.0;
$this->assertEqual(
COMPLETION_COMPLETE_PASS,
completion_info::internal_get_grade_state($item,$grade));
// Item is hidden
$item->hidden=1;
$this->assertEqual(
COMPLETION_COMPLETE,
completion_info::internal_get_grade_state($item,$grade));
// Item isn't hidden but has no pass mark
$item->hidden=0;
$item->gradepass=0;
$this->assertEqual(
COMPLETION_COMPLETE,
completion_info::internal_get_grade_state($item,$grade));
}
}