diff --git a/classes/local/errorover.php b/classes/local/errorover.php
index bf44700..ec38500 100644
--- a/classes/local/errorover.php
+++ b/classes/local/errorover.php
@@ -57,7 +57,69 @@ function exception_grade(\Throwable $exception)
throw new nullException('Error in checking user grades: ' . $exception->getMessage(), 0);
// exit;
}
+function progress_warning($errno, $errstr, $errfile, $errline)
+{
+ // echo"Error stirn --- $errstr";
+ // echo"Error number --- $errno";
+//echo"Error errfile --- $errfile";
+ // echo"Error errline --- $errline";
+ // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean
+ echo " unable to get name ";
+ // throw new nullException('Unable to communicate with LRS. Caught exception: ' . $exception->getMessage() . " Check LRS is up, username and password are correct, and LRS endpoint is correct.", 0);
+ // exit;
+}
+function progresslrsreq_warning($errno, $errstr, $errfile, $errline)
+{
+ // echo"Error stirn --- $errstr";
+ // echo"Error number --- $errno";
+//echo"Error errfile --- $errfile";
+ // echo"Error errline --- $errline";
+ // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean
+ throw new nullException('Unable to communicate with LRS. Caught exception: ' . $exception->getMessage() . " Check LRS is up, username and password are correct, and LRS endpoint is correct.", 0);
+ // exit;
+}
+/**
+ * An exception handler to use in AU cases when many different exceptions for data errors may be thrown.
+ * @param mixed $errno
+ * @param mixed $errstr
+ * @param mixed $errfile
+ * @param mixed $errline
+ * @throws \mod_cmi5launch\local\nullException
+ * @return never
+ */
+function exception_progresslrsreq(\Throwable $exception)
+{
+
+ throw new nullException('Unable to communicate with LRS. Caught exception: ' . $exception->getMessage() . " Check LRS is up, username and password are correct, and LRS endpoint is correct.", 0);
+ // exit;
+}
+function progresslrs_warning($errno, $errstr, $errfile, $errline)
+{
+ // echo"Error stirn --- $errstr";
+ // echo"Error number --- $errno";
+//echo"Error errfile --- $errfile";
+ // echo"Error errline --- $errline";
+ // Maybe we can construct the new errors here. This would allow the error personalization? And keep main code clean
+
+ throw new nullException('Error in retrieving statements from LRS ' . $errstr, 0);
+ // exit;
+}
+/**
+ * An exception handler to use in AU cases when many different exceptions for data errors may be thrown.
+ * @param mixed $errno
+ * @param mixed $errstr
+ * @param mixed $errfile
+ * @param mixed $errline
+ * @throws \mod_cmi5launch\local\nullException
+ * @return never
+ */
+function exception_progresslrs(\Throwable $exception)
+{
+
+ throw new nullException('Error in retrieving statements from LRS ' . $exception->getMessage(), 0);
+ // exit;
+}
function sifting_data_warning($errno, $errstr, $errfile, $errline)
{
// echo"Error stirn --- $errstr";
diff --git a/classes/local/progress.php b/classes/local/progress.php
index 9394ba0..579633d 100644
--- a/classes/local/progress.php
+++ b/classes/local/progress.php
@@ -45,6 +45,12 @@ public function cmi5launch_get_request_statements_from_lrs() {
* @return array
*/
public function cmi5launch_request_statements_from_lrs($registrationid, $session) {
+
+
+ // Set error and exception handler to catch and override the default PHP error messages, to make messages more user friendly.
+ set_error_handler('mod_cmi5launch\local\progresslrs_warning', E_WARNING);
+ set_exception_handler('mod_cmi5launch\local\exception_progresslrs');
+
// Array to hold result.
$result = array();
@@ -55,14 +61,10 @@ public function cmi5launch_request_statements_from_lrs($registrationid, $session
'since' => $session->createdat,
);
- // Try and retrieve statements
+ // Try and retrieve statements.
try {
- $statements = $this->cmi5launch_send_request_to_lrs($data, $session->id);
-/*
- if ($statements === false || $statements == null) {
- throw new \Exception ("No statements found.");
- }
- */
+ $statements = $this->cmi5launch_send_request_to_lrs('cmi5launch_stream_and_send', $data, $session->id);
+
// The results come back as nested array under more then statements. We only want statements, and we want them unique.
$statement = array_chunk($statements["statements"], 1);
@@ -75,9 +77,21 @@ public function cmi5launch_request_statements_from_lrs($registrationid, $session
array_push($result, array($registrationid => $current));
}
+ // Restore default handlers.
+ restore_exception_handler();
+ restore_error_handler();
+
return $result;
+
} catch (\Throwable $e) {
- echo 'Trouble retrieving statements from LRS. Caught exception: ', $e->getMessage(), "\n";
+
+ // Restore default hadlers.
+ restore_exception_handler();
+ restore_error_handler();
+
+ // If there is an error, return the error.
+ throw new nullException('Trouble retrieving statements from LRS. Caught exception: '. $e->getMessage());
+
}
}
@@ -87,18 +101,32 @@ public function cmi5launch_request_statements_from_lrs($registrationid, $session
* @param mixed $id
* @return mixed
*/
- public function cmi5launch_send_request_to_lrs($data, $id) {
+ public function cmi5launch_send_request_to_lrs($cmi5launch_stream_and_send, $data, $id) {
$settings = cmi5launch_settings($id);
- // Url to request statements from.
- $url = $settings['cmi5launchlrsendpoint'] . "statements";
- // Build query with data above.
- $url = $url . '?' . http_build_query($data, "", '&', PHP_QUERY_RFC1738);
+ // Assign passed in function to variable.
+ $stream = $cmi5launch_stream_and_send;
+ // Make sure LRS settings are there.
+ try {
+ // Url to request statements from.
+ $url = $settings['cmi5launchlrsendpoint'] . "statements";
+ // Build query with data above.
+ $url = $url . '?' . http_build_query($data, "", '&', PHP_QUERY_RFC1738);
+
+ // LRS username and password.
+ $user = $settings['cmi5launchlrslogin'];
+ $pass = $settings['cmi5launchlrspass'];
+ }
+ catch (\Throwable $e) {
+
+ // Throw exception if settings are missing.
+ Throw new nullException('Unable to retrieve LRS settings. Caught exception: '. $e->getMessage() . " Check LRS settings are correct.");
+ }
- // LRS username and password.
- $user = $settings['cmi5launchlrslogin'];
- $pass = $settings['cmi5launchlrspass'];
+ // Set error and exception handler to catch and override the default PHP error messages, to make messages more user friendly.
+ set_error_handler('mod_cmi5launch\local\progresslrsreq_warning', E_WARNING);
+ set_exception_handler('mod_cmi5launch\local\exception_progresslrsreq');
// Use key 'http' even if you send the request to https://...
// There can be multiple headers but as an array under the ONE header.
@@ -113,23 +141,29 @@ public function cmi5launch_send_request_to_lrs($data, $id) {
),
),
);
- // The options are here placed into a stream to be sent.
- $context = stream_context_create($options);
- // Sends the stream to the specified URL and stores results.
- // The false is use_include_path, which we dont want in this case, we want to go to the url.
try {
- $result = file_get_contents($url, false, $context);
-
+ //By calling the function this way, it enables encapsulation of the function and allows for testing.
+ //It is an extra step, but necessary for required PHP Unit testing.
+ $result = call_user_func($stream, $options, $url);
+
+ // Decode result.
$resultdecoded = json_decode($result, true);
+
+ // Restore default hadlers.
+ restore_exception_handler();
+ restore_error_handler();
+
return $resultdecoded;
+
} catch (\Throwable $e) {
- echo 'Unable to communicate with LRS. Caught exception: ', $e->getMessage(), "\n";
- echo "
";
- echo " Check LRS is up, username and password are correct, and LRS endpoint is correct.";
- }
+
+ // Restore default hadlers.
+ restore_exception_handler();
+ restore_error_handler();
-
+ throw new nullException('Unable to communicate with LRS. Caught exception: ' . $e->getMessage() . " Check LRS is up, username and password are correct, and LRS endpoint is correct.", 0);
+ }
}
/**
@@ -139,9 +173,22 @@ public function cmi5launch_send_request_to_lrs($data, $id) {
* @return mixed - actor
*/
public function cmi5launch_retrieve_actor($resultarray, $registrationid) {
+
+ // If it fails to parse array it should throw an error, this shouldn't stop execution, but catch so we can send a better message to user.
+ try {
+ // Actor should be in statement.
+ $actor = $resultarray[$registrationid][0]["actor"]["account"]["name"];
+
+ return $actor;
+
+ } catch (\Throwable $e) {
+
+ // If there is an error, echo the error.
- $actor = $resultarray[$registrationid][0]["actor"]["account"]["name"];
- return $actor;
+ echo('Unable to retrieve actor name from LRS. Caught exception: '. $e->getMessage());
+
+ return "(Actor name not retrieved)";
+ }
}
/**
@@ -150,31 +197,41 @@ public function cmi5launch_retrieve_actor($resultarray, $registrationid) {
* @param mixed $registrationid - the registration id
* @return mixed - verb
*/
- public function cmi5launch_retrieve_verbs($resultarray, $registrationid) {
-
- // Some verbs do not have an easy to display 'language' option, we need to check if 'display' is present.
- $verbinfo = $resultarray[$registrationid][0]["verb"];
- $display = array_key_exists("display", $verbinfo);
-
- // If it is null then there is no display, so go by verb id.
- if (!$display) {
- // Retrieve id.
- $verbid = $resultarray[$registrationid][0]["verb"]["id"];
-
- // Splits id in two on 'verbs/', we want the end which is the actual verb.
- $split = explode('verbs/', $verbid);
- $verb = $split[1];
-
- } else {
- // If it is not null then there is a language easy to read version of verb display, such as 'en' or 'en-us'.
- $verblang = $resultarray[$registrationid][0]["verb"]["display"];
- // Retrieve the language.
- $lang = array_key_first($verblang);
- // Use it to retrieve verb.
- $verb = [$verblang][0][$lang];
- }
+ public function cmi5launch_retrieve_verb($resultarray, $registrationid)
+ {
+
+ // Encase the whole thing in a try catch block to catch any errors.
+ // If an array key isn't there it will throw a warning. It will not stop execution but catching it will enable us to send better error messages.
+
+ try {
+ // Some verbs do not have an easy to display 'language' option, we need to check if 'display' is present.
+ $verbinfo = $resultarray[$registrationid][0]["verb"];
+ $display = array_key_exists("display", $verbinfo);
+
+ // If it is null then there is no display, so go by verb id.
+ if (!$display) {
+ // Retrieve id.
+ $verbid = $resultarray[$registrationid][0]["verb"]["id"];
- return $verb;
+ // Splits id in two on 'verbs/', we want the end which is the actual verb.
+ $split = explode('verbs/', $verbid);
+ $verb = $split[1];
+
+ } else {
+ // If it is not null then there is a language easy to read version of verb display, such as 'en' or 'en-us'.
+ $verblang = $resultarray[$registrationid][0]["verb"]["display"];
+ // Retrieve the language.
+ $lang = array_key_first($verblang);
+ // Use it to retrieve verb.
+ $verb = [$verblang][0][$lang];
+ }
+
+ return $verb;
+ } catch (\Throwable $e) {
+ // If there is an error, echo the error.
+ echo('Unable to retrieve verb from LRS. Caught exception: '. $e->getMessage());
+ return "(Verb not retrieved)";
+ }
}
/**
@@ -189,66 +246,58 @@ public function cmi5launch_retrieve_verbs($resultarray, $registrationid) {
public function cmi5launch_retrieve_object_name($resultarray, $registrationid) {
global $CFG;
+ // Encase the whole thing in a try catch block to catch any errors.
+ // If an array key isn't there it will throw a warning. It will not stop execution but catching it will enable us to send better error messages.
+ try {
- // First find the object, it should always be second level of statement (so third level array).
- if (array_key_exists("object", $resultarray[$registrationid][0])) {
-
- if (array_key_exists("definition", $resultarray[$registrationid][0]["object"])) {
-
- // If 'definition' exists, check if 'name' does.
- if (array_key_exists("name", $resultarray[$registrationid][0]["object"]["definition"])) {
-
- // Retrieve the name.
- $objectarray = $resultarray[$registrationid][0]["object"]["definition"]["name"];
-
- // There may be more than one languages string to choose from. First we want to
- // select the language that matches the language of the course, then if not available, the first key.
- // System language setting.
- $language = $CFG->lang;
- if (array_key_exists($language, $objectarray)) {
- $object = $objectarray[$language];
- } else {
- $defaultlanguage = array_key_first($objectarray);
- $object = $objectarray[$defaultlanguage];
+ // First find the object, it should always be second level of statement (so third level array).
+ if (array_key_exists("object", $resultarray[$registrationid][0])) {
+
+ if (array_key_exists("definition", $resultarray[$registrationid][0]["object"])) {
+
+ // If 'definition' exists, check if 'name' does.
+ if (array_key_exists("name", $resultarray[$registrationid][0]["object"]["definition"])) {
+
+ // Retrieve the name.
+ $objectarray = $resultarray[$registrationid][0]["object"]["definition"]["name"];
+
+ // There may be more than one languages string to choose from. First we want to
+ // select the language that matches the language of the course, then if not available, the first key.
+ // System language setting.
+ $language = $CFG->lang;
+
+ if (array_key_exists($language, $objectarray)) {
+ $object = $objectarray[$language];
+
+ } else {
+ $defaultlanguage = array_key_first($objectarray);
+ $object = $objectarray[$defaultlanguage];
+
+ }
+ return $object;
}
- return $object;
- }
- } else if (array_key_exists("id", $resultarray[$registrationid][0]["object"])) {
+ } else if (array_key_exists("id", $resultarray[$registrationid][0]["object"])) {
+
+ // If name is missing check for id.
+ // Retrieve id.
+ $object = $resultarray[$registrationid][0]["object"]["id"];
+
+ return $object;
- // If name is missing check for id.
- // Retrieve id.
- $object = $resultarray[$registrationid][0]["object"]["id"];
- return $object;
+ } else {
+
+ return "(Object name not retrieved/there is no object in this statement)";
+ }
} else {
-
- // If both name and id are missing throw error.
- $this->cmi5launch_statement_retrieval_error("Object name and id ");
+
+ return "(Object name not retrieved/there is no object in this statement)";
}
-
- } else {
-
- $this->cmi5launch_statement_retrieval_error("Object ");
- }
- }
-
- /**
- * Error message for statment retrieval to mark if something is missing
- * @param mixed $missingitem - the missing item(s)
- * @return void
- */
- public function cmi5launch_statement_retrieval_error($missingitem) {
-
- global $CFG;
-
- // If admin debugging is enabled.
- if ($CFG->debugdeveloper) {
-
- // Print that it is missing.
- echo "
";
- echo $missingitem . "is missing from this statement.";
- echo "
";
+ } catch (\Throwable $e) {
+ // If there is an error, echo the error.
+ echo('Unable to retrieve object name from LRS. Caught exception: '. $e->getMessage());
+ return "(Object name not retrieved)";
}
}
@@ -260,20 +309,28 @@ public function cmi5launch_statement_retrieval_error($missingitem) {
*/
public function cmi5launch_retrieve_timestamp($resultarray, $registrationid) {
- // Verify this statement has a 'timestamp' param.
- if (array_key_exists("timestamp", $resultarray[$registrationid][0])) {
+ // Encase the whole thing in a try catch block to catch any errors.
+ // If an array key isn't there it will throw a warning. It will not stop execution but catching it will enable us to send better error messages.
+ try {
+ // Verify this statement has a 'timestamp' param.
+ if (array_key_exists("timestamp", $resultarray[$registrationid][0])) {
- $date = new \DateTime($resultarray[$registrationid][0]["timestamp"], new \DateTimeZone('US/Eastern'));
+ $date = new \DateTime($resultarray[$registrationid][0]["timestamp"], new \DateTimeZone('US/Eastern'));
- $date->setTimezone(new \DateTimeZone('America/New_York'));
+ $date->setTimezone(new \DateTimeZone('America/New_York'));
- $date = $date->format('d-m-Y' . " " . 'h:i a');
+ $date = $date->format('d-m-Y' . " " . 'h:i a');
- return $date;
+ return $date;
- } else {
+ } else {
- $this->cmi5launch_statement_retrieval_error("Timestamp ");
+ return "(Timestamp not retrieved or not present in statement)";
+ }
+ } catch (\Throwable $e) {
+ // If there is an error, echo the error.
+ echo('Unable to retrieve timestamp from LRS. Caught exception: '. $e->getMessage());
+ return "(Timestamp not retrieved)";
}
}
@@ -293,40 +350,48 @@ public function cmi5launch_retrieve_score($resultarray, $registrationid) {
// Variable to hold score.
$score = null;
- // Verify this statement has a 'result' param.
- if (array_key_exists("result", $resultarray[$registrationid][0])) {
-
- // If it exists, retrieve it.
- $resultinfo = $resultarray[$registrationid][0]["result"];
-
- $score = array_key_exists("score", $resultinfo);
+ // Encase the whole thing in a try catch block to catch any errors.
+ // If an array key isn't there it will throw a warning. It will not stop execution but catching it will enable us to send better error messages.
+ try {
+ // Verify this statement has a 'result' param.
+ if (array_key_exists("result", $resultarray[$registrationid][0])) {
- // If it is null then the item in question doesn't exist in this statement.
- if ($score) {
+ // If it exists, retrieve it.
+ $resultinfo = $resultarray[$registrationid][0]["result"];
- $score = $resultarray[$registrationid][0]["result"]["score"];
+ // If it is null then the item in question doesn't exist in this statement.
+ if (array_key_exists("score", $resultinfo)) {
- // Raw score preferred to scaled.
- if ($score["raw"]) {
+ $score = $resultarray[$registrationid][0]["result"]["score"];
+;
+ // Raw score preferred to scaled.
+ if (array_key_exists("raw", $score)) {
- $returnscore = $score["raw"];
- return $returnscore;
- } else if ($score["scaled"]) {
+ $returnscore = $score["raw"];
+
+ return $returnscore;
- $returnscore = round($score["scaled"], 2);
- return $returnscore;
+ } else if (array_key_exists("scaled", $score)) {
+
+ $returnscore = round($score["scaled"], 2);
+
+ return $returnscore;
+ }
}
+ else {
+
+ return "(Score not retrieved or not present in statement)";
+ }
+ } else {
+
+ return "(Score not retrieved or not present in statement)";
}
- } else {
-
- // If admin debugging is enabled.
- if ($CFG->debugdeveloper) {
-
- // Print that it is missing.
- echo "
";
- echo 'No score in statement with id ' .$resultarray[$registrationid][0]['id'];
- echo "
";
- }
+ } catch (\Throwable $e) {
+
+ // If there is an error, echo the error.
+ echo('Unable to retrieve score from LRS. Caught exception: '. $e->getMessage());
+
+ return "(Score not retrieved)";
}
}
@@ -345,95 +410,73 @@ public function cmi5launch_retrieve_statements($registrationid, $session) {
// Array to hold score and be returned.
$returnscore = 0;
- $resultdecoded = $this->cmi5launch_request_statements_from_lrs($registrationid, $session);
-
- // We need to sort the statements by finding their session id
- // parse through array 'ext' to find the one holding session id.
- foreach ($resultdecoded as $singlestatement) {
-
- $code = $session->code;
- $currentsessionid = "";
- $ext = $singlestatement[$registrationid][0]["context"]["extensions"];
- foreach ($ext as $key => $value) {
+ // Wrap in a try catch block to catch any errors.
+ try {
+ $resultdecoded = $this->cmi5launch_request_statements_from_lrs($registrationid, $session);
+
+ // We need to sort the statements by finding their session id
+ // parse through array 'ext' to find the one holding session id.
+ foreach ($resultdecoded as $singlestatement) {
- // If key contains "sessionid" in string.
- if (str_contains($key, "sessionid")) {
- $currentsessionid = $value;
- }
- }
+ $code = $session->code;
+ $currentsessionid = "";
- // Now if code equals currentsessionid, this is a statement pertaining to this session.
- if ($code === $currentsessionid) {
+ // what is first array key in statement? It is the registration id.
+
+ //// There should always be an extension but in case.
+ try {
+ $ext = $singlestatement[$registrationid][0]["context"]["extensions"];
- $actor = $this->cmi5launch_retrieve_actor($singlestatement, $registrationid);
- $verb = $this->cmi5launch_retrieve_verbs($singlestatement, $registrationid);
- $object = $this->cmi5launch_retrieve_object_name($singlestatement, $registrationid);
- $date = $this->cmi5launch_retrieve_timestamp($singlestatement, $registrationid);
- $score = $this->cmi5launch_retrieve_score($singlestatement, $registrationid);
+ foreach ($ext as $key => $value) {
- // If a session has more than one score, we only want the highest.
- if (!$score == null && $score > $returnscore) {
+ // If key contains "sessionid" in string.
+ if (str_contains($key, "sessionid")) {
- $returnscore = $score;
+ $currentsessionid = $value;
+ }
+ }
+ } catch (\Throwable $e) {
+ // If there is an error, echo the error.
+ echo('Unable to retrieve session id from LRS. Caught exception: '. $e->getMessage() . ". There may not be an extension key in statement.");
}
- // Update to return.
- $progressupdate[] = "$actor $verb $object on $date";
-
- }
-
- }
-
- $session->progress = json_encode($progressupdate);
-
- $session->score = $returnscore;
-
- return $session;
- }
+ // Now if code equals currentsessionid, this is a statement pertaining to this session.
+ if ($code === $currentsessionid) {
- // An error message catcher.
- /**
- * Function to test returns from cmi5 player and display error message if found to be false
- * // or not 200.
- * @param mixed $resulttotest - The result to test.
- * @param string $type - The type missing to be added to the error message.
- * @return bool
- */
- public static function cmi5launch_progress_error_message($resulttotest, $type) {
-
- // Decode result because if it is not 200 then something went wrong
- // If it's a string, decode it.
- if (is_string($resulttotest)) {
- $resulttest = json_decode($resulttotest, true);
- } else {
- $resulttest = $resulttotest;
- }
+ $actor = $this->cmi5launch_retrieve_actor($singlestatement, $registrationid);
+ $verb = $this->cmi5launch_retrieve_verb($singlestatement, $registrationid);
+ $object = $this->cmi5launch_retrieve_object_name($singlestatement, $registrationid);
+ $date = $this->cmi5launch_retrieve_timestamp($singlestatement, $registrationid);
+ $score = $this->cmi5launch_retrieve_score($singlestatement, $registrationid);
- // I think splittin these to return two seperate messages deppennnding on whether player is running is better.
- // Player cannot return an error if not runnin,
- if ($resulttest === false ){
+ // If a session has more than one score, we only want the highest.
+ if (!$score == null && $score > $returnscore) {
- echo "
";
+ $returnscore = $score;
+ }
- echo "Something went wrong " . $type . ". LRS is not communicating. Is it running?";
+ // Update to return.
+ $progressupdate[] = "$actor $verb $object on $date";
- echo "
";
+ }
- return false;
- }
- else if( array_key_exists("statusCode", $resulttest) && $resulttest["statusCode"] != 200) {
+ }
- echo "
";
+ $session->progress = json_encode($progressupdate);
- echo "Something went wrong " . $type . ". CMI5 Player returned " . $resulttest["statusCode"] . " error. With message '"
- . $resulttest["message"] . "'." ;
- echo "
";
+ $session->score = $returnscore;
- return false;
- } else {
+ return $session;
- // No errors, continue.
- return true;
+ } catch (\Throwable $e) {
+
+ // If there is an error, echo the error.
+ echo('Unable to retrieve statements from LRS. Caught exception: '. $e->getMessage());
+
+
+ return "(Statements not retrieved)";
}
}
+
+
}
diff --git a/cmi5PHP/tests/cmi5TestHelpers.php b/cmi5PHP/tests/cmi5TestHelpers.php
index c867dbc..69658ca 100644
--- a/cmi5PHP/tests/cmi5TestHelpers.php
+++ b/cmi5PHP/tests/cmi5TestHelpers.php
@@ -127,7 +127,7 @@ function deletetestcmi5launch_sessions($ids)
foreach ($ids as $id) {
// Delete the cmi5launch record
- $DB->delete_records('cmi5launch_sessions', array('id' => $id));
+ $DB->delete_records('cmi5launch_sessions', array('sessionid' => $id));
}
}
@@ -173,43 +173,6 @@ function maketestaus ($testcourseid)
{
global $DB, $cmi5launch, $USER;
- // Mock values to make AUs.
- /*
- $mockvalues = array(
- 'id' => 'id',
- 'attempt' => 'attempt',
- 'url' => 'url',
- 'type' => 'type',
- 'lmsid' => 'lmsid',
- 'grade' => 'grade',
- 'scores' => 'scores',
- 'title' => array(0 => array('text' => 'title')),
- 'moveon' => 'moveon',
- 'auindex' => 'auindex',
- 'parents' => 'parents',
- 'objectives' => 'objectives',
- 'description' => array(0 => array('text' => 'description')),
- 'activitytype' => 'activitytype',
- 'launchmethod' => 'launchmethod',
- 'masteryscore' => 'masteryscore',
- 'satisfied' => 'satisfied',
- 'launchurl' => 'launchurl',
- 'sessions' => 'sessions',
- 'progress' => 'progress',
- 'noattempt' => 'noattempt',
- 'completed' => 'completed',
- 'passed' => 'passed',
- 'inprogress' => 'inprogress',
- 'masteryScore' => 'masteryScore',
- 'launchMethod' => 'launchMethod',
- 'lmsId' => 'lmsId',
- 'moveOn' => 'moveOn',
- 'auIndex' => 'auIndex',
- 'activityType' => 'activityType',
- 'moodlecourseid' => 'moodlecourseid',
- 'userid' => 'userid'
- );
-*/
// Make new AUs, lets make five.
$aus = array();
for ($i = 0; $i < 5; $i++) {
@@ -273,10 +236,313 @@ function maketestaus ($testcourseid)
}
/**
- * Create fake statements for testing.
- * @param mixed $amountomake - amount of statements to make.
- * @return array $statements - array of statements
- */
+ * Create fake statement values for testing.
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvalues($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => '2024-' . $i . '0-00T00:00:00.000Z' ,
+ 'actor' => array (
+ "firstname" => "firstname" . $i,
+ "lastname" => "lastname" . $i,
+ "account" => array (
+ "homePage" => "homePage" . $i,
+ "name" => "actorname" . $i,
+ ),
+ ),
+ 'verb' => array (
+ "id" => "verbs/verbid" . $i,
+ "display" => array(
+ "en" => ("verbdisplay" . $i),
+ ),
+ ),
+ 'object' => array (
+ "id" => "objectid" . $i,
+ "definition" => array (
+ "name" => array (
+
+ "en" => 'objectname' . $i),
+ "description" => "description" . $i,
+ "type" => "type" . $i,
+ ),
+ ),
+ 'context' => array (
+ "context" => "context" . $i,
+ "contexttype" => "contexttype" . $i,
+ "contextparent" => "contextparent" . $i,
+ "extensions" => array (
+ "extensions" => "extensions" . $i,
+ "sessionid" => "code" . $i,
+ ),
+ ),
+ "result" => array (
+ "result" => "result" . $i,
+ "score" => array (
+ "raw" => 80 + $i,
+ "scaled" => $i,
+ ),
+ ),
+ 'stored' => 'stored' . $i,
+ 'authority' => array (
+ "authority" => "authority" . $i,
+
+ ),
+ 'version' => "version" . $i,
+ 'code' => 'code' . $i,
+ 'progress' => 'progress' . $i,
+ 'score' => 'score' . $i,
+ ),
+ )
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has no 'display' key in the verb.
+ * It also has a scaled score for testing in testcmi5launch_retrieve_score_scaled_score
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluesnodisplay($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => 'timestamp' . $i,
+ 'actor' => array (
+ "firstname" => "firstname" . $i,
+ "lastname" => "lastname" . $i,
+ "account" => array (
+ "homePage" => "homePage" . $i,
+ "name" => "name" . $i,
+ ),
+ ),
+ 'verb' => array (
+ "id" => "verbs/verbid" . $i,
+ ),
+ 'version' => "version" . $i,
+
+ "result" => array (
+ "result" => "result" . $i,
+ "score" => array (
+ "scaled" => $i,
+ ),
+ ),
+ )
+ ));
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has no object key.
+ * // It also has no result and is used in testcmi5launch_retrieve_result_no_result
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluesnoobject($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => 'timestamp' . $i,),
+ )
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has no object definition key but does have an id.
+ * // This also has no timestamp so it can be used for testing in testcmi5launch_retrieve_timestamp_no_time
+ * // And no score in 'result' to be use in testin testcmi5launch_retrieve_score_no_score.
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluesnoobjectdef($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'object' => array (
+ "id" => "objectid" . $i),
+
+ "result" => array (),
+ )
+ ));
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has no object/def/name key..
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluesnoobjectname($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => 'timestamp' . $i,),
+ 'object' => array (
+ "id" => "objectid" . $i,
+ "definition" => array (
+
+ "description" => "description" . $i,
+ "type" => "type" . $i,
+ ),
+
+ ),
+ )
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has an object but nothing in it .
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluesnoobjectid($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => 'timestamp' . $i,
+ 'object' => array ()
+ )
+ )
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+
+ /**
+ * Create fake statement values for testing.
+ * This one has no matching lanuage string.
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluenomatchinglang($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => 'timestamp' . $i,
+ 'object' => array (
+ "id" => "objectid" . $i,
+ "definition" => array (
+ "name" => array(
+ "fr" => "fr" . $i,
+ "es" => "name" . $i,
+ ),
+ "description" => "description" . $i,
+ "type" => "type" . $i,
+ ),
+
+ ),
+ ) )
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+ /**
+ * Create fake statement values for testing.
+ * This one has a matching lanuage value.
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
+function maketeststatementsvaluematchinglang($amounttomake, $registrationid)
+{
+ for($i = 0; $i < $amounttomake; $i++)
+ {
+ // Mock statements that should be returned.
+ $statementvalues[] = array(
+ $registrationid => array(
+ // They are nested under 0 since array_chunk is used.
+ 0 => array(
+ 'timestamp' => '2024-' . $i . '0-00T00:00:00.000Z',
+ 'object' => array (
+ "id" => "objectid" . $i,
+ "definition" => array (
+ "name" => array(
+ "en" => "en-us" . $i,
+ "es" => "name" . $i,
+ ),
+ "description" => "description" . $i,
+ "type" => "type" . $i,
+ ),
+
+ ),
+ ))
+ );
+ }
+
+ // Return the statement values.
+ return $statementvalues;
+}
+
+/**
+ * Create fake statements for testing.
+ * @param mixed $amountomake - amount of statements to make.
+ * @return array $statements - array of statements
+ */
function maketeststatements($amounttomake)
{
// Iterate through amount to make, and use i to make different 'registration ids'
@@ -294,58 +560,63 @@ function maketeststatements($amounttomake)
// Array to hold the statements.
// Maybe I need to change the stucture so the $i is first and next to statements instead of now as its nested
- /*old
- $statement['statements'][] = array(
- $i => array(*/
- $statement['statements'][$i] = array(
- // 'id' => 'idune' . $i,
- 'timestamp' => 'timestamp' . $i,
- 'actor' => array (
- "firstname" => "firstname" . $i,
- "lastname" => "lastname" . $i,
- "account" => array (
- "homePage" => "homePage" . $i,
- "name" => "name" . $i,
- ),
+ $newstatement = array(
+ 'timestamp' => '2024-' . $i . '0-00T00:00:00.000Z' ,
+ 'actor' => array (
+ "firstname" => "firstname" . $i,
+ "lastname" => "lastname" . $i,
+ "account" => array (
+ "homePage" => "homePage" . $i,
+ "name" => "actorname" . $i,
),
- 'verb' => array (
- "id" => "verbid" . $i,
- "display" => array(
- "en" => "verbdisplay" . $i,
- ),
- )
- ,
- 'object' => array (
- "id" => "objectid" . $i,
- "definition" => array (
- "name" => "name" . $i,
- "description" => "description" . $i,
- "type" => "type" . $i,
- ),
+ ),
+ 'verb' => array (
+ "id" => "verbs/verbid" . $i,
+ "display" => array(
+ "en" => ("verbdisplay" . $i),
),
- 'context' => array (
- "context" => "context" . $i,
- "contexttype" => "contexttype" . $i,
- "contextparent" => "contextparent" . $i,
+ ),
+ 'object' => array (
+ "id" => "objectid" . $i,
+ "definition" => array (
+ "name" => array (
+
+ "en" => 'objectname' . $i),
+ "description" => "description" . $i,
+ "type" => "type" . $i,
),
- "result" => array (
- "result" => "result" . $i,
- "score" => array (
- "raw" => "raw" . $i,
- "scaled" => "scaled" . $i,
- ),
+ ),
+ 'context' => array (
+ "context" => "context" . $i,
+ "contexttype" => "contexttype" . $i,
+ "contextparent" => "contextparent" . $i,
+ "extensions" => array (
+ "extensions" => "extensions" . $i,
+ "sessionid" => "code" . $i,
),
- 'stored' => 'stored' . $i,
- 'authority' => array (
- "authority" => "authority" . $i,
-
+ ),
+ "result" => array (
+ "result" => "result" . $i,
+ "score" => array (
+ "raw" => 80 + $i,
+ "scaled" => $i,
),
- 'version' => "version" . $i,
+ ),
+ 'stored' => 'stored' . $i,
+ 'authority' => array (
+ "authority" => "authority" . $i,
+
+ ),
+ 'version' => "version" . $i,
+ 'code' => 'code' . $i,
+ 'progress' => 'progress' . $i,
+ 'score' => 'score' . $i,
);
- $statements[] = $statement;
+ $statements[] = $newstatement;
}
+ $statement['statements'] = $statements;
// Return array of statements
return $statement;
}
@@ -365,16 +636,13 @@ function maketestsessions ()
for ($i = 0; $i < 5; $i++) {
-
- //$toaddtostring = strval($i);
- // Add i to each value so the AUs are unique.
- // Mock values to make sessions.
// For some bizarre reason, retrieve sessions from db goes on SESSION id not ID?!?!??
// THIS IS the problem?
$mockvalues = array(
'id' => $i,
- 'sessionid' => 'sessionid' . $i,
+ // Can't save string to DB.
+ 'sessionid' => $i,
'userid' => 'userid' . $i,
'moodlecourseid' => 'moodlecourseid' . $i,
'registrationscoursesausid' => 'registrationscoursesausid' . $i,
@@ -400,30 +668,24 @@ function maketestsessions ()
'launchurl' => 'launchurl' . $i,
);
$sessions[] = new session($mockvalues);
- $sessionid[] = ('sessionid' . $i);
+ $sessionid[] = ( $i);
}
- // Pass in the au index to retrieve a launchurl and session id.
-//$urldecoded = $cmi5launchretrieveurl($cmi5launch->id, $auindex);
-
-// Retrieve and store session id in the aus table.
-//$sessionid = intval($urldecoded['id']);
-
-
-// Retrieve the launch url.
-$launchurl = 'testurl';
-// And launch method.
-$launchmethod = 'testmethod';
-// Now save the fake sessions to the test database
-// Ok so tomorrow make this so there are sessions actually creatd.
-$sessionhelper = new session_helpers();
-//$createsession = $sessionhelper->cmi5launch_create_session();
- // For each session id in the list, create a session.
- foreach ($sessions as $session) {
- // LEts test if it can retrieve here
- $newid = $sessionhelper->cmi5launch_create_session($session->id, $launchurl, $launchmethod);
- $newids[] = $newid;
- //$sessionid[] = $session;
+ // Retrieve the launch url.
+ $launchurl = 'testurl';
+ // And launch method.
+ $launchmethod = 'testmethod';
+
+ // Now save the fake sessions to the test database
+ // Ok so tomorrow make this so there are sessions actually creatd.
+ $sessionhelper = new session_helpers();
+ //$createsession = $sessionhelper->cmi5launch_create_session();
+ // For each session id in the list, create a session.
+ foreach ($sessions as $session) {
+ // LEts test if it can retrieve here
+ $newid = $sessionhelper->cmi5launch_create_session($session->id, $launchurl, $launchmethod);
+ $newids[] = $newid;
+ //$sessionid[] = $session;
@@ -437,7 +699,7 @@ function maketestsessions ()
}
/**
- * Heeelper func that assigns the sessions made to the aus for testing purposes.
+ * Helper func that assigns the sessions made to the aus for testing purposes.
* @param mixed $auids
* @param mixed $sessionids
* @return array
@@ -472,14 +734,6 @@ function assign_sessions_to_aus($auids, $sessionids){
// Tomorrow: no that isnt it. Something else is throwin the problem.
// Now the AU will have properties and we want to assign the sessionid array to the 'sessions' property
$au->sessions = json_encode($sessionids);
- // Update AU in table with new info.
-
- //echo au here nd check what sessons itr and if id mathces
-
-
-
- // what is au record?
-
// Save the AU back to the DB.
$success = $DB->update_record('cmi5launch_aus', $au);
@@ -489,13 +743,6 @@ function assign_sessions_to_aus($auids, $sessionids){
$newaus[] = $au;
}
- // AHA! They are whole damn aus
- // now save the new aus back to db
- // we dont need to sve twice!!!
- // $save_aus($newaus);
- // Save us is to make new aus we need to save them back to DB
- // Now update to table.
- //return $newauids;
}
@@ -545,36 +792,27 @@ function assign_aus_to_courses($courseids, $auids){
}
}
-
-
-
-
-
-/*
- function get_file_get_contents() {
- return ['file_get_contents'];
-}
-*/
- global $file_get_contents;
- // Ok lets make a file_et_contents for this namespace, we know it should return a json string?
- // And what should it receive? just the reular arguments?
- /**
- * A local file_get_contents to overide the PHP function for testing.
- * As we do not want to actually get the file, we just want to test the function calling that function.
- *
- */
- function file_get_contents($url, $use_include_path = false, $context = null, $offset = 0, $maxlen = null)
+ // So now all the test has to do is inject THIS which will return as we please
+ function cmi5launch_test_stream_and_send_pass_lrs($options, $url)
{
- // Do we wamt to test whats passed in as well? pr ois that not necessary?
- // MAybe we can return the args as json encoded string?
- return json_encode(func_get_args());
+ // Make a fake statement to return from the mock.
+ $statement = maketeststatements(1);
+
+ // Lets pass in the 'return' value as the option.
+ // Encode because it would be a string comiiiiing from LRS.
+ return json_encode($statement);
}
- // And what should it receive? just the reular arguments?
- /**
- * A local file_get_contents to overide the PHP function for testing.
- * As we do not want to actually get the file, we just want to test the function calling that function.
- *
- */
+
+ // So now all the test has to do is inject THIS which will return as we please
+ function cmi5launch_test_stream_and_send_excep_lrs($options, $url)
+ {
+ // Make a fake statement to return from the mock.
+ $statement = maketeststatements(1);
+
+ // Lets pass in the 'return' value as the option.
+ // Encode because it would be a string comiiiiing from LRS.
+ return json_encode($statement);
+ }
// So now all the test has to do is inject THIS which will return as we please
function cmi5launch_test_stream_and_send_pass($options, $url)
diff --git a/cmi5PHP/tests/grade_helpersTest.php b/cmi5PHP/tests/grade_helpersTest.php
index a18304e..1286f4d 100644
--- a/cmi5PHP/tests/grade_helpersTest.php
+++ b/cmi5PHP/tests/grade_helpersTest.php
@@ -705,7 +705,7 @@ public function testcmi5launch_update_au_for_user_grades_excep()
// Functions from other classes.
$updateau = $gradehelper->get_cmi5launch_update_au_for_user_grades();
- // The expected is built bby the two messages knowing 'title' is an empty array.
+ // The expected is built by the two messages knowing 'title' is an empty array.
$expected = "Error in updating or checking user grades. Report this error to system administrator: Error in checking user grades:";
// Catch the exception.
diff --git a/cmi5PHP/tests/progressTest.php b/cmi5PHP/tests/progressTest.php
index 014332f..209ac39 100644
--- a/cmi5PHP/tests/progressTest.php
+++ b/cmi5PHP/tests/progressTest.php
@@ -3,6 +3,8 @@
use PHPUnit\Framework\TestCase;
use mod_cmi5launch\local\cmi5_connectors;
+use mod_cmi5launch\local\nullException;
+use mod_cmi5launch\local\session;
require_once( "cmi5TestHelpers.php");
@@ -51,9 +53,18 @@ protected function setUp(): void
{
global $sessionids, $DB, $cmi5launch, $cmi5launchid, $USER, $testcourseid, $cmi5launchsettings;
- $cmi5launchsettings = array("cmi5launchtenanttoken" => "Testtoken", "cmi5launchplayerurl" => "http://test/launch.php", "cmi5launchcustomacchp" => "http://testhomepage.com");
+ $cmi5launchsettings = array(
+ "cmi5launchlrsendpoint" => "Test LRS point",
+ "cmi5launchlrslogin" => "Test LRS login",
+ "cmi5launchlrspass" => "Test LRS password",
+ "cmi5launchtenanttoken" => "Testtoken",
+ "cmi5launchplayerurl" => "http://test/launch.php",
+ "cmi5launchcustomacchp" => "http://testhomepage.com",
+ "grademethod" => 1
+ );
+
// Override global variable and function so that it returns test data.
$USER = new \stdClass();
$USER->username = "testname";
@@ -68,9 +79,12 @@ protected function setUp(): void
protected function tearDown(): void
{
+ global $sessionids;
// Restore overridden global variable.
unset($GLOBALS['USER']);
unset($GLOBALS['cmi5launchsettings']);
+
+ deletetestcmi5launch_sessions($sessionids);
}
/**
@@ -93,66 +107,13 @@ public function testcmi5launch_request_statements_from_lrs_pass()
$registrationid = "registrationid";
// Statement values that should be returned from mock.
- $statementvalues = array();
+ $statementvalues = maketeststatementsvalues($amount, $registrationid);
- for($i = 0; $i < $amount; $i++)
- {
- // Mock statements that should be returned.
- $statementvalues[] = array(
- $registrationid => array(
- // They are nested under 0 since array_chunk is used.
- 0 => array(
- 'timestamp' => 'timestamp' . $i,
- 'actor' => array (
- "firstname" => "firstname" . $i,
- "lastname" => "lastname" . $i,
- "account" => array (
- "homePage" => "homePage" . $i,
- "name" => "name" . $i,
- ),
- ),
- 'verb' => array (
- "id" => "verbid" . $i,
- "display" => array(
- "en" => "verbdisplay" . $i,
- ),
- ),
- 'object' => array (
- "id" => "objectid" . $i,
- "definition" => array (
- "name" => "name" . $i,
- "description" => "description" . $i,
- "type" => "type" . $i,
- ),
- ),
- 'context' => array (
- "context" => "context" . $i,
- "contexttype" => "contexttype" . $i,
- "contextparent" => "contextparent" . $i,
- ),
- "result" => array (
- "result" => "result" . $i,
- "score" => array (
- "raw" => "raw" . $i,
- "scaled" => "scaled" . $i,
- ),
- ),
- 'stored' => 'stored' . $i,
- 'authority' => array (
- "authority" => "authority" . $i,
-
- ),
- 'version' => "version" . $i,
- ),
- )
- );
- }
-
// Retrieve a sessionid, we'll just use the first one.
$sessionid = $sessionids[0];
// Retrieve a session from the DB as an object.
- $session = $DB->get_record('cmi5launch_sessions', array('id' => $sessionid), '*', MUST_EXIST);
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid), '*', MUST_EXIST);
// Mock data as it will be passed to stub.
$data = array(
@@ -160,6 +121,9 @@ public function testcmi5launch_request_statements_from_lrs_pass()
'since' => $session->createdat,
);
+ // Function that will be called in function under test.
+ $testfunction = 'cmi5launch_stream_and_send';
+
// Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods.
// Create a mock of the send_request class as we don't actually want
// to create a new course in the player.
@@ -169,7 +133,7 @@ public function testcmi5launch_request_statements_from_lrs_pass()
$csc->expects($this->once())
->method('cmi5launch_send_request_to_lrs')
- ->with($data, $session->id)
+ ->with($testfunction, $data, $session->id)
->willReturn($statements);
// Call the method under test.
@@ -187,78 +151,1008 @@ public function testcmi5launch_request_statements_from_lrs_pass()
* Test of the cmi5launch_request_statements_from_lrs with a fail condition.
* @return void
*/
- public function testcmi5launch_request_statements_from_lrs_fail(){
+ public function testcmi5launch_request_statements_from_lrs_excep(){
global $DB, $cmi5launch, $cmi5launchid, $sessionids;
- // Amount of statements to make for testing.
- // The same amount of statements to make for testing will match the amount
- // of statement values returned from mock.
- $amount = 5;
+
+ // Test registrationid to pass.
+ $registrationid = "registrationid";
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[0];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid), '*', MUST_EXIST);
- // Make fake statements for testing.
- $statements = maketeststatements($amount);
+ // Mock data as it will be passed to stub.
+ $data = array(
+ 'registration' => $registrationid,
+ 'since' => $session->createdat,
+ );
+
+ // Function that will be called in function under test.
+ $testfunction = 'cmi5launch_stream_and_send';
+
+ // Mock a cmi5 connector object but only stub ONE method, as we want to test the other methods.
+ // Create a mock of the send_request class as we don't actually want
+ // to create a new course in the player.
+ $csc = $this->getMockBuilder('mod_cmi5launch\local\progress')
+ ->onlyMethods(array('cmi5launch_send_request_to_lrs' ))
+ ->getMock();
+
+ // If this returns null it should trrigger an error in the function.
+ $csc->expects($this->once())
+ ->method('cmi5launch_send_request_to_lrs')
+ ->with($testfunction, $data, $session->id)
+ ->willReturn(null);
+
+ // The expected is built by the two messages knowing 'title' is an empty array.
+ $expected = "Trouble retrieving statements from LRS. Caught exception: ";
+
+ // Catch the exception.
+ $this->expectException(nullException::class);
+ $this->expectExceptionMessage($expected);
+
+ // Call the method under test.
+ $result = $csc->cmi5launch_request_statements_from_lrs($registrationid,$session);
+
+
+ }
+ /**
+ * Test of the cmi5launch_send_request_to_lrs with a pass condition.
+ * @return void
+ */
+ public function testcmi5launch_send_request_to_lrs(){
+ global $DB, $cmi5launch, $cmi5launchid, $sessionids;
+
+ // Mock data as it will be passed to stub.
+ $data = array(
+ 'registration' => "registrationid",
+ 'since' => "Test time",
+ );
+
+ // Retrieve settings like they will be in SUT.
+ $settings = cmi5launch_settings($cmi5launch->id);
+ // Url to request statements from.
+ $url = $settings['cmi5launchlrsendpoint'] . "statements";
+ // Build query with data above.
+ $url = $url . '?' . http_build_query($data, "", '&', PHP_QUERY_RFC1738);
+
+ // LRS username and password.
+ $user = $settings['cmi5launchlrslogin'];
+ $pass = $settings['cmi5launchlrspass'];
+
+
// Test registrationid to pass.
$registrationid = "registrationid";
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[0];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid), '*', MUST_EXIST);
- // Statement values that should be returned from mock.
- $statementvalues = array();
-
-
- for($i = 0; $i < $amount; $i++)
+ // Mock data as it will be passed to stub.
+ // Use key 'http' even if you send the request to https://...
+ // There can be multiple headers but as an array under the ONE header.
+ // Content(body) must be JSON encoded here, as that is what CMI5 player accepts.
+ $options = array(
+ 'http' => array(
+ 'method' => 'GET',
+ 'header' => array(
+ 'Authorization: Basic ' . base64_encode("$user:$pass"),
+ "Content-Type: application/json\r\n" .
+ "X-Experience-API-Version:1.0.3",
+ ),
+ ),
+ );
+
+ // Function that will be called in function under test.
+ $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_pass_lrs';
+
+ // Make a fake statement to return from the mock.
+ $statement = maketeststatements(1);
+
+ // The result we expect back is the statment, decoded. So it's original form.
+ $expected = $statement;
+
+ // New proggress
+ $progress = new \mod_cmi5launch\local\progress();
+ // Call the method under test.
+ $result = $progress->cmi5launch_send_request_to_lrs($testfunction, $data, $session->id);
+
+ // Check the result is as expected.
+ $this->assertEquals($expected, $result, "Expected result to match statementvalues ");
+ // The return should also be an array, since it is decoded with the 'tue' flag.
+ $this->assertIsArray($result,"Expected retrieved object to be array" );
+ }
+
+ /**
+ * Test of the cmi5launch_send_request_to_lrs with a fail condition.
+ * Throws an exception at the first try/catch where it is retrievin settings.
+ * @return void
+ */
+ public function testcmi5launch_send_request_to_lrs_fail_settings(){
+
+ global $DB, $cmi5launch, $cmi5launchid, $sessionids;
+
+ // Make data that is not array to throw error in settings try/catch
+ $data = ("Test string to throw error");
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[0];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid), '*', MUST_EXIST);
+
+
+ // Function that will be called in function under test.
+ $testfunction = 'cmi5Test\cmi5launch_test_stream_and_send_pass_lrs';
+
+ // New proggress
+ $progress = new \mod_cmi5launch\local\progress();
+ // The expected is built bby the two messages knowing 'title' is an empty array.
+ $expected = "Unable to retrieve LRS settings. Caught exception: ";
+
+
+ $this->expectExceptionMessage($expected);
+ // Catch the exception.
+ $this->expectException(nullException::class);
+
+ // Call the method under test.
+ $result = $progress->cmi5launch_send_request_to_lrs($testfunction, $data, $session->id);
+
+ }
+
+ /**
+ * Test of the cmi5launch_send_request_to_lrs with a fail condition.
+ * Throws an exception at the second try/catch, where it tries to communicte with LRS.
+ * @return void
+ */
+ public function testcmi5launch_send_request_to_lrs_fail_excep(){
+
+ global $DB, $cmi5launch, $cmi5launchid, $sessionids;
+
+ // Mock data as it will be passed to stub.
+ $data = array(
+ 'registration' => "registrationid",
+ 'since' => "Test time",
+ );
+
+ // Retrieve settings like they will be in SUT.
+ $settings = cmi5launch_settings($cmi5launch->id);
+ // Url to request statements from.
+ $url = $settings['cmi5launchlrsendpoint'] . "statements";
+ // Build query with data above.
+ $url = $url . '?' . http_build_query($data, "", '&', PHP_QUERY_RFC1738);
+
+ // LRS username and password.
+ $user = $settings['cmi5launchlrslogin'];
+ $pass = $settings['cmi5launchlrspass'];
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[0];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid), '*', MUST_EXIST);
+
+ // Mock data as it will be passed to stub.
+ // Use key 'http' even if you send the request to https://...
+ // There can be multiple headers but as an array under the ONE header.
+ // Content(body) must be JSON encoded here, as that is what CMI5 player accepts.
+ $options = array(
+ 'http' => array(
+ 'method' => 'GET',
+ 'header' => array(
+ 'Authorization: Basic ' . base64_encode("$user:$pass"),
+ "Content-Type: application/json\r\n" .
+ "X-Experience-API-Version:1.0.3",
+ ),
+ ),
+ );
+
+ // Function that will be called in function under test.
+ $testfunction = 'cmi5Test\cmi5launch_stream_and_send_excep_lrs';
+
+
+ // The expected is built bby the two messages knowing 'title' is an empty array.
+ $expected = 'Unable to communicate with LRS. Caught exception: ' ;
+
+ // Catch the exception.
+ $this->expectException(nullException::class);
+ $this->expectExceptionMessage($expected);
+
+ // New proggress
+ $progress = new \mod_cmi5launch\local\progress();
+ // Call the method under test.
+ $result = $progress->cmi5launch_send_request_to_lrs($testfunction, $data, $session->id);
+
+ }
+ /**
+ * Test of the cmi5launch_retrieve_actor with a pass condition.
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_actor_pass()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "actorname0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_actor($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+ /**
+ * Test of the cmi5launch_retrieve_actor with a fail condition.
+ * Fail at retrieving the actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_actor_fail()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "(Actor name not retrieved)";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ // Pass a string that is not in the statement to cause an error.
+ $result = $progress->cmi5launch_retrieve_actor($statement[0], "purple");
+
+ $expectedoutput = 'Unable to retrieve actor name from LRS. Caught exception: Undefined array key "purple"';
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+ $this->expectOutputString($expectedoutput);
+ }
+ /**
+ * Test of the cmi5launch_retrieve_verb with a pass condition.
+ * (This one tests if verb has display option).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_verb_pass()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "verbdisplay0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_verb($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+/**
+ * Test of the cmi5launch_retrieve_verb with a pass condition.
+ * (This one tests if verb doesn't have a display option).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_verb_pass_no_display()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnodisplay(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "verbid0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_verb($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_actor with a fail condition.
+ * Fail at retrieving the verb .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_verb_fail()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "(Verb not retrieved)";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ // Pass a string that is not in the statement to cause an error.
+ $result = $progress->cmi5launch_retrieve_verb($statement[0], "purple");
+
+ $expectedoutput = 'Unable to retrieve verb from LRS. Caught exception: Undefined array key "purple"';
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+ $this->expectOutputString($expectedoutput);
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if object isn't there).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_pass_no_object_key()
+ {
+ // Branch one
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobject(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "(Object name not retrieved/there is no object in this statement)";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if object doesn't have a definition key and no id ).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_pass_no_object_def_key()
+ {
+ //Branch 2
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobjectid(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "(Object name not retrieved/there is no object in this statement)";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if object doesnt have a definition key,
+ * but does have an object id key ).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_pass_object_id_exists()
+ {
+ // Branch 3
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobjectdef(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "objectid0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if object has everything and languae is specified matches the cfg language (should be 'en')).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_pass_matching_lang()
+ {
+ // Branch 5
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluematchinglang(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "en-us0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if object has everything and languae doesnt match the cfg language).
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_pass_no_matching_lang()
+
+ {
+ // Branch 4.
+
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluenomatchinglang(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "fr0";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+ /**
+ * Test of the cmi5launch_retrieve_object with a pass condition.
+ * (This one tests if the exceptions are caught and thrown correctly.
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_object_excep()
+ {
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = "String to throw error";
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $expected = "(Object name not retrieved)";
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_object_name($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ // There will also be an output message.
+ $expectedoutput = 'Unable to retrieve object name from LRS. Caught exception: Cannot access offset of type string on string';
+ $this->expectOutputString($expectedoutput);
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_timestamp with a pass condition.
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_timestamp()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // The actor name will be 'name1' Because 1 was passed but index starts at '0' in value making function.
+ $faketime = "2024-00-00T00:00:00.000Z";
+
+ // Turn expected into a date so it matches what's leaving the function.
+ $expected = new \DateTime($faketime, new \DateTimeZone('US/Eastern'));
+
+ $expected->setTimezone(new \DateTimeZone('America/New_York'));
+
+ $expected = $expected->format('d-m-Y' . " " . 'h:i a');
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_timestamp($statement[0], $registrationid);
+ // echo" result . " . $result;
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_timestamp with a pass condition.
+ * Tests else branch if timestamp is not present.
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_timestamp_no_time()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobjectdef(1, $registrationid);
+
+ $expected = "(Timestamp not retrieved or not present in statement)";
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_timestamp($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+
+ /**
+ * Test of the cmi5launch_retrieve_timestamp with a fail condition.
+ * Tests error try/catch.
+ * Successfully retrieves actors name.
+ * @return void
+ */
+ public function testcmi5launch_retrieve_timestamp_excep()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = "String to throw error";
+
+ $expected = "(Timestamp not retrieved)";
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_timestamp($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a string");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ // There will also be an output message.
+ $expectedoutput = 'Unable to retrieve timestamp from LRS. Caught exception: Cannot access offset of type string on string';
+ $this->expectOutputString($expectedoutput);
+ }
+
+
+ /**
+ * Test of the cmi5launch_retrieve_score with a pass condition.
+ * Successfully retrieves a score
+ * // This one retrieves raw score
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_score_raw_score()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvalues(1, $registrationid);
+
+ // Make the statement have a score.
+ $statement[0][$registrationid][0]['result']['score']['raw'] = 10;
+ $expected = 10;
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_score($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsInt($result, "Expected result to be a integer");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_score with a pass condition.
+ * Successfully retrieves a scaled score
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_score_scaled_score()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnodisplay(1, $registrationid);
+
+ // Make the statement have a score.
+ // Give it a float to test rounding.
+ $statement[0][$registrationid][0]['result']['score']['scaled'] = 10.504;
+
+ $expected = 10.5;
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_score($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsFloat($result, "Expected result to be a integer");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_score with a pass condition.
+ * Successfully returns a message there is no score in the statement.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_score_no_score()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobjectdef(1, $registrationid);
+
+ $expected = "(Score not retrieved or not present in statement)";
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_score($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a integer");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+
+ /**
+ * Test of the cmi5launch_retrieve_score with a pass condition.
+ * Successfully returns a message there is no result in the statement.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_score_no_result()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = maketeststatementsvaluesnoobject(1, $registrationid);
+
+ $expected = "(Score not retrieved or not present in statement)";
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_score($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a integer");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_score with a fail condition.
+ * Successfully returns an exception.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_score_excep()
+
+ {
+ global $CFG;
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make a test statement to draw name from.
+ $statement = "String to throw error";
+
+ $expected = "(Score not retrieved)";
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Because we have a new function to make these values in a test environment, the
+ // statement comes wrapped in an array, so access first level of array.
+ $result = $progress->cmi5launch_retrieve_score($statement[0], $registrationid);
+
+ // The result should be a string.
+ $this->assertIsString($result, "Expected result to be a integer");
+ // and should equal expected value.
+ $this->assertEquals($expected, $result, "Expected result to match expected value");
+
+ // There will also be an output message.
+ $expectedoutput = 'Unable to retrieve score from LRS. Caught exception: Cannot access offset of type string on string';
+ $this->expectOutputString($expectedoutput);
+ }
+
+ /**
+ * Test of the cmi5launch_retrieve_statements with a pass condition.
+ * Successfully returns a session object.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_statements()
+
{
- // Mock statements that should be returned.
- $statementvalues[] = array(
- $registrationid => array(
- // They are nested under 0 since array_chunk is used.
- 0 => array(
- 'timestamp' => 'timestamp' . $i,
- 'actor' => array (
- "firstname" => "firstname" . $i,
- "lastname" => "lastname" . $i,
- "account" => array (
- "homePage" => "homePage" . $i,
- "name" => "name" . $i,
- ),
- ),
- 'verb' => array (
- "id" => "verbid" . $i,
- "display" => array(
- "en" => "verbdisplay" . $i,
- ),
- ),
- 'object' => array (
- "id" => "objectid" . $i,
- "definition" => array (
- "name" => "name" . $i,
- "description" => "description" . $i,
- "type" => "type" . $i,
- ),
- ),
- 'context' => array (
- "context" => "context" . $i,
- "contexttype" => "contexttype" . $i,
- "contextparent" => "contextparent" . $i,
- ),
- "result" => array (
- "result" => "result" . $i,
- "score" => array (
- "raw" => "raw" . $i,
- "scaled" => "scaled" . $i,
- ),
- ),
- 'stored' => 'stored' . $i,
- 'authority' => array (
- "authority" => "authority" . $i,
-
- ),
- 'version' => "version" . $i,
- ),
- )
- );
+ global $CFG, $DB, $sessionids;
+
+ // First create a fake session to pass to the function.
+ $sessions = maketestsessions();
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[1];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid));
+ //
+ // add a code to session
+ $session->code = "code0";
+ // add a score to be graded
+ $session->score = 80;
+ // add a progress to be graded
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make test statements to pass through from the mock function;
+ $statement = (maketeststatementsvalues(1, $registrationid));
+
+ // Make an array to add information to the session.
+ $newprogress = json_encode(["actorname0 verbdisplay0 objectname0 on 29-11-2023 07:00 pm"]);
+ $newscore = (80);
+
+ // Copy the session so that we can tweak it and make how it should be then
+ // Compare with sessin object returned from the function.
+ $newsession = $session;
+ // Now update the session to match the expected session.
+ // Add the progress and score to the session.
+ $newsession->progress = $newprogress;
+ $newsession->score = $newscore;
+
+ $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\progress')
+ ->onlyMethods(array('cmi5launch_request_statements_from_lrs'))
+ ->getMock();
+
+ // Mock returns statements, as it would be from the LRS.
+ $mockedclass->expects($this->once())
+ ->method('cmi5launch_request_statements_from_lrs')
+ ->with($registrationid, $session)
+ ->willReturn($statement);
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Call the method under test.
+ $result = $mockedclass->cmi5launch_retrieve_statements($registrationid, $session);
+
+ // The result should be a session.
+ $this->assertIsObject($result, "Expected result to be a session");
+ // and should equal expected value.
+ $this->assertEquals($newsession, $result, "Expected result to match expected value");
+
}
-
+
+ /**
+ * Test of the cmi5launch_retrieve_statements with a condition.
+ * Successfully catches an exception thrown when trying to retrieve extension info.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_statements_excep_ext()
+
+ {
+ global $CFG, $DB, $sessionids;
+
+ // First create a fake session to pass to the function.
+ $sessions = maketestsessions();
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[1];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid));
+ //
+ // add a code to session
+ $session->code = "code0";
+ // add a score to be graded
+ $session->score = 80;
+ // add a progress to be graded
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make test statements to pass through from the mock function;
+ $statement = maketeststatementsvaluesnoobject(1, $registrationid);
+
+ // Make an array to add information to the session.
+ $newprogress = json_encode(["actorname0 verbdisplay0 objectname0 on 29-11-2023 07:00 pm"]);
+ $newscore = (80);
+
+ // Copy the session so that we can tweak it and make how it should be then
+ // Compare with sessin object returned from the function.
+ $newsession = $session;
+ // Now update the session to match the expected session.
+ // Add the progress and score to the session.
+ $newsession->progress = $newprogress;
+ $newsession->score = $newscore;
+
+ $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\progress')
+ ->onlyMethods(array('cmi5launch_request_statements_from_lrs'))
+ ->getMock();
+
+ // Mock returns statements, as it would be from the LRS.
+ $mockedclass->expects($this->once())
+ ->method('cmi5launch_request_statements_from_lrs')
+ ->with($registrationid, $session)
+ ->willReturn($statement);
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Call the method under test.
+ $result = $mockedclass->cmi5launch_retrieve_statements($registrationid, $session);
+
+ // There will also be an output message.
+ $expectedoutput = 'Unable to retrieve session id from LRS. Caught exception: Undefined array key "context". There may not be an extension key in statement.';
+ $this->expectOutputString($expectedoutput);
+
}
+ /**
+ * Test of the cmi5launch_retrieve_statements with a condition.
+ * Successfully catches an exception thrown.
+ * .
+ * @return void
+ */
+ public function testcmi5launch_retrieve_statements_excep()
+
+ {
+ global $CFG, $DB, $sessionids;
+
+ // First create a fake session to pass to the function.
+ $sessions = maketestsessions();
+
+ // Retrieve a sessionid, we'll just use the first one.
+ $sessionid = $sessionids[1];
+
+ // Retrieve a session from the DB as an object.
+ $session = $DB->get_record('cmi5launch_sessions', array('sessionid' => $sessionid));
+ //
+ // add a code to session
+ $session->code = "code0";
+ // add a score to be graded
+ $session->score = 80;
+ // add a progress to be graded
+
+ // Fake registration id.
+ $registrationid = "registrationid";
+ // Make test statements to pass through from the mock function;
+ $statement = "String to throw error";
+
+ // Make an array to add information to the session.
+ $newprogress = json_encode(["actorname0 verbdisplay0 objectname0 on 29-11-2023 07:00 pm"]);
+ $newscore = (80);
+
+ // Copy the session so that we can tweak it and make how it should be then
+ // Compare with sessin object returned from the function.
+ $newsession = $session;
+ // Now update the session to match the expected session.
+ // Add the progress and score to the session.
+ $newsession->progress = $newprogress;
+ $newsession->score = $newscore;
+
+ $mockedclass = $this->getMockBuilder('mod_cmi5launch\local\progress')
+ ->onlyMethods(array('cmi5launch_request_statements_from_lrs'))
+ ->getMock();
+
+ // Mock returns statements, as it would be from the LRS.
+ $mockedclass->expects($this->once())
+ ->method('cmi5launch_request_statements_from_lrs')
+ ->with($registrationid, $session)
+ ->willReturn($statement);
+
+ // Progress class and SUT.
+ $progress = new \mod_cmi5launch\local\progress();
+ // Call the method under test.
+ $result = $mockedclass->cmi5launch_retrieve_statements($registrationid, $session);
+
+ // There will also be an output message.
+ $expectedoutput = 'Unable to retrieve statements from LRS. Caught exception: foreach() argument must be of type array|object, string given';
+ $this->expectOutputString($expectedoutput);
+
+ }
}
\ No newline at end of file