diff --git a/grade/import/csv/tests/fixtures/phpunit_gradeimport_csv_load_data.php b/grade/import/csv/tests/fixtures/phpunit_gradeimport_csv_load_data.php new file mode 100644 index 00000000000..ad80e519ed6 --- /dev/null +++ b/grade/import/csv/tests/fixtures/phpunit_gradeimport_csv_load_data.php @@ -0,0 +1,122 @@ +. + +require_once($CFG->dirroot . '/grade/import/csv/classes/load_data.php'); +require_once($CFG->dirroot . '/grade/import/lib.php'); + +/** + * Class to open up private methods in gradeimport_csv_load_data(). + */ +class phpunit_gradeimport_csv_load_data extends gradeimport_csv_load_data { + + /** + * Method to open up the appropriate method for unit testing. + * + * @param object $record + * @param int $studentid + */ + public function test_insert_grade_record($record, $studentid) { + $this->importcode = 00001; + $this->insert_grade_record($record, $studentid); + } + + /** + * Method to open up the appropriate method for unit testing. + */ + public function get_importcode() { + return $this->importcode; + } + + /** + * Method to open up the appropriate method for unit testing. + * + * @param array $header The column headers from the CSV file. + * @param int $key Current row identifier. + * @param string $value The value for this row (final grade). + * @return array new grades that are ready for commiting to the gradebook. + */ + public function test_import_new_grade_item($header, $key, $value) { + $this->newgradeitems = null; + $this->importcode = 00001; + return $this->import_new_grade_item($header, $key, $value); + } + + /** + * Method to open up the appropriate method for unit testing. + * + * @param string $value The value, from the csv file, being mapped to identify the user. + * @param array $userfields Contains the field and label being mapped from. + * @return int Returns the user ID if it exists, otherwise null. + */ + public function test_check_user_exists($value, $userfields) { + return $this->check_user_exists($value, $userfields); + } + + /** + * Method to open up the appropriate method for unit testing. + * + * @param int $courseid The course ID. + * @param int $itemid The ID of the grade item that the feedback relates to. + * @param string $value The actual feedback being imported. + * @return object Creates a feedback object with the item ID and the feedback value. + */ + public function test_create_feedback($courseid, $itemid, $value) { + return $this->create_feedback($courseid, $itemid, $value); + } + + /** + * Method to open up the appropriate method for unit testing. + */ + public function test_update_grade_item($courseid, $map, $key, $verbosescales, $value) { + return $this->update_grade_item($courseid, $map, $key, $verbosescales, $value); + } + + /** + * Method to open up the appropriate method for unit testing. + * + * @param int $courseid The course ID. + * @param array $map Mapping information provided by the user. + * @param int $key The line that we are currently working on. + * @param bool $verbosescales Form setting for grading with scales. + * @param string $value The grade value . + * @return array grades to be updated. + */ + public function test_map_user_data_with_value($mappingidentifier, $value, $header, $map, $key, $courseid, $feedbackgradeid, + $verbosescales) { + // Set an import code. + $this->importcode = 00001; + $this->map_user_data_with_value($mappingidentifier, $value, $header, $map, $key, $courseid, $feedbackgradeid, + $verbosescales); + + switch ($mappingidentifier) { + case 'userid': + case 'useridnumber': + case 'useremail': + case 'username': + return $this->studentid; + break; + case 'new': + return $this->newgrades; + break; + case 'feedback': + return $this->newfeedbacks; + break; + default: + return $this->newgrades; + break; + } + } +} diff --git a/grade/import/csv/tests/load_data_test.php b/grade/import/csv/tests/load_data_test.php new file mode 100644 index 00000000000..790f889b814 --- /dev/null +++ b/grade/import/csv/tests/load_data_test.php @@ -0,0 +1,430 @@ +. + +/** + * Unit tests for the class in load_data.php + * + * @package gradeimport_csv + * @category phpunit + * @copyright 2014 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/grade/import/csv/tests/fixtures/phpunit_gradeimport_csv_load_data.php'); +require_once($CFG->libdir . '/csvlib.class.php'); +require_once($CFG->libdir . '/grade/grade_item.php'); +require_once($CFG->libdir . '/grade/tests/fixtures/lib.php'); + +/** + * Unit tests for lib.php + * + * @package gradeimport_csv + * @copyright 2014 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class gradeimport_csv_load_data_testcase extends grade_base_testcase { + + /** @var string $oktext Text to be imported. This data should have no issues being imported. */ + protected $oktext = '"First name",Surname,"ID number",Institution,Department,"Email address","Assignment: Assignment for grape group", "Feedback: Assignment for grape group","Course total" +Anne,Able,,"Moodle HQ","Rock on!",student7@mail.com,56.00,"We welcome feedback",56.00 +Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00'; + + /** @var string $badtext Text to be imported. This data has an extra column and should not succeed in being imported. */ + protected $badtext = '"First name",Surname,"ID number",Institution,Department,"Email address","Assignment: Assignment for grape group","Course total" +Anne,Able,,"Moodle HQ","Rock on!",student7@mail.com,56.00,56.00,78.00 +Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,75.00'; + + /** @var int $iid Import ID. */ + protected $iid; + + /** @var object $csvimport a csv_import_reader object that handles the csv import. */ + protected $csvimport; + + /** @var array $columns The first row of the csv file. These are the columns of the import file.*/ + protected $columns; + + /** + * Load up the above text through the csv import. + * + * @param string $content Text to be imported into the gradebook. + * @return array All text separated by commas now in an array. + */ + protected function csv_load($content) { + // Import the csv strings. + $this->iid = csv_import_reader::get_new_iid('grade'); + $this->csvimport = new csv_import_reader($this->iid, 'grade'); + + $this->csvimport->load_csv_content($content, 'utf8', 'comma'); + $this->columns = $this->csvimport->get_columns(); + + $this->csvimport->init(); + while ($line = $this->csvimport->next()) { + $testarray[] = $line; + } + + return $testarray; + } + + /** + * Test loading data and returning preview content. + */ + public function test_load_csv_content() { + $encoding = 'utf8'; + $separator = 'comma'; + $previewrows = 5; + $csvpreview = new phpunit_gradeimport_csv_load_data(); + $csvpreview->load_csv_content($this->oktext, $encoding, $separator, $previewrows); + + $expecteddata = array(array( + 'Anne', + 'Able', + '', + 'Moodle HQ', + 'Rock on!', + 'student7@mail.com', + 56.00, + 'We welcome feedback', + 56.00 + ), + array( + 'Bobby', + 'Bunce', + '', + 'Moodle HQ', + 'Rock on!', + 'student5@mail.com', + 75.00, + '', + 75.00 + ) + ); + + $expectedheaders = array( + 'First name', + 'Surname', + 'ID number', + 'Institution', + 'Department', + 'Email address', + 'Assignment: Assignment for grape group', + 'Feedback: Assignment for grape group', + 'Course total' + ); + // Check that general data is returned as expected. + $this->assertEquals($csvpreview->get_previewdata(), $expecteddata); + // Check that headers are returned as expected. + $this->assertEquals($csvpreview->get_headers(), $expectedheaders); + + // Check that errors are being recorded. + $csvpreview = new phpunit_gradeimport_csv_load_data(); + $csvpreview->load_csv_content($this->badtext, $encoding, $separator, $previewrows); + // Columns shouldn't match. + $this->assertEquals($csvpreview->get_error(), get_string('csvweirdcolumns', 'error')); + } + + /** + * Test fetching grade items for the course. + */ + public function test_fetch_grade_items() { + + $gradeitemsarray = grade_item::fetch_all(array('courseid' => $this->courseid)); + $gradeitems = phpunit_gradeimport_csv_load_data::fetch_grade_items($this->courseid); + + // Make sure that each grade item is located in the gradeitemsarray. + foreach ($gradeitems as $key => $gradeitem) { + $this->assertArrayHasKey($key, $gradeitemsarray); + } + + // Get the key for a specific grade item. + $quizkey = null; + foreach ($gradeitemsarray as $key => $value) { + if ($value->itemname == "Quiz grade item") { + $quizkey = $key; + } + } + + // Expected modified item name. + $testitemname = get_string('modulename', $gradeitemsarray[$quizkey]->itemmodule) . ': ' . + $gradeitemsarray[$quizkey]->itemname; + // Check that an item that is a module, is concatenated properly. + $this->assertEquals($testitemname, $gradeitems[$quizkey]); + } + + /** + * Test the inserting of grade record data. + */ + public function test_insert_grade_record() { + global $DB, $USER; + + $user = $this->getDataGenerator()->create_user(); + $this->setAdminUser(); + + $record = new stdClass(); + $record->itemid = 4; + $record->newgradeitem = 25; + $record->finalgrade = 62.00; + $record->feedback = 'Some test feedback'; + + $testobject = new phpunit_gradeimport_csv_load_data(); + $testobject->test_insert_grade_record($record, $user->id); + + $gradeimportvalues = $DB->get_records('grade_import_values'); + // Get the insert id. + $key = key($gradeimportvalues); + + $testarray = array(); + $testarray[$key] = new stdClass(); + $testarray[$key]->id = $key; + $testarray[$key]->itemid = $record->itemid; + $testarray[$key]->newgradeitem = $record->newgradeitem; + $testarray[$key]->userid = $user->id; + $testarray[$key]->finalgrade = $record->finalgrade; + $testarray[$key]->feedback = $record->feedback; + $testarray[$key]->importcode = $testobject->get_importcode(); + $testarray[$key]->importer = $USER->id; + + // Check that the record was inserted into the database. + $this->assertEquals($gradeimportvalues, $testarray); + } + + /** + * Test preparing a new grade item for import into the gradebook. + */ + public function test_import_new_grade_item() { + global $DB; + + $this->setAdminUser(); + $this->csv_load($this->oktext); + $columns = $this->columns; + + // The assignment is item 6. + $key = 6; + $testobject = new phpunit_gradeimport_csv_load_data(); + + // Key for this assessment. + $this->csvimport->init(); + $testarray = array(); + while ($line = $this->csvimport->next()) { + $testarray[] = $testobject->test_import_new_grade_item($columns, $key, $line[$key]); + } + + // Query the database and check how many results were inserted. + $newgradeimportitems = $DB->get_records('grade_import_newitem'); + $this->assertEquals(count($testarray), count($newgradeimportitems)); + } + + /** + * Check that the user matches a user in the system. + */ + public function test_check_user_exists() { + + // Need to add one of the users into the system. + $user = new stdClass(); + $user->firstname = 'Anne'; + $user->lastname = 'Able'; + $user->email = 'student7@mail.com'; + $userdetail = $this->getDataGenerator()->create_user($user); + + $testobject = new phpunit_gradeimport_csv_load_data(); + + $testarray = $this->csv_load($this->oktext); + + $userfields = array('field' => 'email', 'label' => 'Email address'); + // If the user exists then the user id is returned. + $userid = $testobject->test_check_user_exists($testarray[0][5] , $userfields); + // Check that the user id returned matches with the user that we created. + $this->assertEquals($userid, $userdetail->id); + + // Check for failure. + // Try for an exception. + $userfields = array('field' => 'id', 'label' => 'userid'); + $userid = $testobject->test_check_user_exists($testarray[0][0], $userfields); + // Check that the userid is null. + $this->assertNull($userid); + + // Expected error message. + $mappingobject = new stdClass(); + $mappingobject->field = $userfields['label']; + $mappingobject->value = $testarray[0][0]; + $expectederrormessage = get_string('usermappingerror', 'grades', $mappingobject); + // Check that expected error message and actual message match. + $gradebookerrors = $testobject->get_gradebookerrors(); + $this->assertEquals($expectederrormessage, $gradebookerrors[0]); + + // The field mapping is correct, but the student does not exist. + $userid = $testobject->test_check_user_exists($testarray[1][5], $userfields); + // Check that the userid is null. + $this->assertNull($userid); + + // Expected error message. + $mappingobject = new stdClass(); + $mappingobject->field = $userfields['label']; + $mappingobject->value = $testarray[1][5]; + $expectederrormessage = get_string('usermappingerror', 'grades', $mappingobject); + // Check that expected error message and actual message match. + $gradebookerrors = $testobject->get_gradebookerrors(); + // This is the second error in the array of gradebook errors. + $this->assertEquals($expectederrormessage, $gradebookerrors[1]); + } + + /** + * Test preparing feedback for inserting / updating into the gradebook. + */ + public function test_create_feedback() { + + $testarray = $this->csv_load($this->oktext); + $testobject = new phpunit_gradeimport_csv_load_data(); + + // Try to insert some feedback for an assessment. + $feedback = $testobject->test_create_feedback($this->courseid, 1, $testarray[0][7]); + + // Expected result. + $expectedfeedback = array('itemid' => 1, 'feedback' => $testarray[0][7]); + $this->assertEquals((array)$feedback, $expectedfeedback); + } + + /** + * Test preparing grade_items for upgrading into the gradebook. + */ + public function test_update_grade_item() { + + $testarray = $this->csv_load($this->oktext); + $testobject = new phpunit_gradeimport_csv_load_data(); + + // We're not using scales so no to this option. + $verbosescales = 0; + // Map and key are to retrieve the grade_item that we are updating. + $map = array(1); + $key = 0; + // We return the new grade array for saving. + $newgrades = $testobject->test_update_grade_item($this->courseid, $map, $key, $verbosescales, $testarray[0][6]); + + $expectedresult = array(); + $expectedresult[0] = new stdClass(); + $expectedresult[0]->itemid = 1; + $expectedresult[0]->finalgrade = $testarray[0][6]; + + $this->assertEquals($newgrades, $expectedresult); + + // Try sending a bad grade value (A letter instead of a float / int). + $newgrades = $testobject->test_update_grade_item($this->courseid, $map, $key, $verbosescales, 'A'); + // The $newgrades variable should be null. + $this->assertNull($newgrades); + $expectederrormessage = get_string('badgrade', 'grades'); + // Check that the error message is what we expect. + $gradebookerrors = $testobject->get_gradebookerrors(); + $this->assertEquals($expectederrormessage, $gradebookerrors[0]); + } + + /** + * Test importing data and mapping it with items in the course. + */ + public function test_map_user_data_with_value() { + // Need to add one of the users into the system. + $user = new stdClass(); + $user->firstname = 'Anne'; + $user->lastname = 'Able'; + $user->email = 'student7@mail.com'; + $userdetail = $this->getDataGenerator()->create_user($user); + + $testarray = $this->csv_load($this->oktext); + $testobject = new phpunit_gradeimport_csv_load_data(); + + // We're not using scales so no to this option. + $verbosescales = 0; + // Map and key are to retrieve the grade_item that we are updating. + $map = array(1); + $key = 0; + + // Test new user mapping. This should return the user id if there were no problems. + $userid = $testobject->test_map_user_data_with_value('useremail', $testarray[0][5], $this->columns, $map, $key, + $this->courseid, $map[$key], $verbosescales); + $this->assertEquals($userid, $userdetail->id); + + $newgrades = $testobject->test_map_user_data_with_value('new', $testarray[0][6], $this->columns, $map, $key, + $this->courseid, $map[$key], $verbosescales); + // Check that the final grade is the same as the one inserted. + $this->assertEquals($testarray[0][6], $newgrades[0]->finalgrade); + + $feedback = $testobject->test_map_user_data_with_value('feedback', $testarray[0][7], $this->columns, $map, $key, + $this->courseid, $map[$key], $verbosescales); + // Expected result. + $resultarray = array(); + $resultarray[0] = new stdClass(); + $resultarray[0]->itemid = 1; + $resultarray[0]->feedback = $testarray[0][7]; + $this->assertEquals($feedback, $resultarray); + + // Default behaviour (update a grade item). + $newgrades = $testobject->test_map_user_data_with_value('default', $testarray[0][6], $this->columns, $map, $key, + $this->courseid, $map[$key], $verbosescales); + $this->assertEquals($testarray[0][6], $newgrades[0]->finalgrade); + } + + /** + * Test importing data into the gradebook. + */ + public function test_prepare_import_grade_data() { + global $DB; + + // Need to add one of the users into the system. + $user = new stdClass(); + $user->firstname = 'Anne'; + $user->lastname = 'Able'; + $user->email = 'student7@mail.com'; + // Insert user 1. + $this->getDataGenerator()->create_user($user); + $user = new stdClass(); + $user->firstname = 'Bobby'; + $user->lastname = 'Bunce'; + $user->email = 'student5@mail.com'; + // Insert user 2. + $this->getDataGenerator()->create_user($user); + + $this->csv_load($this->oktext); + + $importcode = 007; + $verbosescales = 0; + + // Form data object. + $formdata = new stdClass(); + $formdata->mapfrom = 5; + $formdata->mapto = 'useremail'; + $formdata->mapping_0 = 0; + $formdata->mapping_1 = 0; + $formdata->mapping_2 = 0; + $formdata->mapping_3 = 0; + $formdata->mapping_4 = 0; + $formdata->mapping_5 = 0; + $formdata->mapping_6 = 'new'; + $formdata->mapping_7 = 'feedback_2'; + $formdata->mapping_8 = 0; + $formdata->map = 1; + $formdata->id = 2; + $formdata->iid = $this->iid; + $formdata->importcode = $importcode; + + // Blam go time. + $testobject = new phpunit_gradeimport_csv_load_data(); + $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', + $verbosescales); + // If everything inserted properly then this should be true. + $this->assertTrue($dataloaded); + } +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 853b4eef932..ddd676cc2f3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -64,6 +64,7 @@ lib/grade/tests grade/tests grade/grading/tests + grade/import/csv/tests availability/tests