diff --git a/admin/tool/uploadcourse/classes/helper.php b/admin/tool/uploadcourse/classes/helper.php index 917e265ee3c..72444e1b144 100644 --- a/admin/tool/uploadcourse/classes/helper.php +++ b/admin/tool/uploadcourse/classes/helper.php @@ -60,10 +60,10 @@ class tool_uploadcourse_helper { * * @param array|object $data course data. * @param string $templateshortname template of shortname. - * @return null|string shortname based on the template. + * @return null|string shortname based on the template, or null when an error occured. */ public static function generate_shortname($data, $templateshortname) { - if (is_null($templateshortname)) { + if (empty($templateshortname) && !is_numeric($templateshortname)) { return null; } if (strpos($templateshortname, '%') === false) { @@ -71,30 +71,32 @@ class tool_uploadcourse_helper { } $course = (object) $data; - $shortname = isset($course->shortname) ? $course->shortname : ''; $fullname = isset($course->fullname) ? $course->fullname : ''; $idnumber = isset($course->idnumber) ? $course->idnumber : ''; - $callback = partial(array('tool_uploadcourse_helper', 'generate_shortname_callback'), $shortname, $fullname, $idnumber); + $callback = partial(array('tool_uploadcourse_helper', 'generate_shortname_callback'), $fullname, $idnumber); $result = preg_replace_callback('/(?proceed(); } + public function test_proceed_when_already_started() { + $this->resetAfterTest(true); + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data); + $this->assertTrue($co->prepare()); + $co->proceed(); + $this->setExpectedException('coding_exception'); + $co->proceed(); + } + + public function test_invalid_shortname() { + $this->resetAfterTest(true); + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('shortname' => '', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data); + $this->assertFalse($co->prepare()); + $this->assertArrayHasKey('invalidshortname', $co->get_errors()); + } + public function test_create() { global $DB; $this->resetAfterTest(true); @@ -497,6 +519,7 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $this->resetAfterTest(true); $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1')); + $c2 = $this->getDataGenerator()->create_course(array('shortname' => 'c2')); // Cannot rename when creating. $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; @@ -566,6 +589,24 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $this->assertEquals('c1', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id))); $this->assertEquals('New summary!', $DB->get_field_select('course', 'summary', 'id = :id', array('id' => $c1->id))); $this->assertEquals('Another fullname!', $DB->get_field_select('course', 'fullname', 'id = :id', array('id' => $c1->id))); + + // Renaming with invalid shortname. + $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; + $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; + $importoptions = array('canrename' => true); + $data = array('shortname' => 'c1', 'rename' => 'invalid'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertFalse($co->prepare()); + $this->assertArrayHasKey('invalidshortname', $co->get_errors()); + + // Renaming with invalid shortname. + $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; + $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; + $importoptions = array('canrename' => true); + $data = array('shortname' => 'c1', 'rename' => 'c2'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertFalse($co->prepare()); + $this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors()); } public function test_restore_course() { @@ -779,7 +820,7 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { public function test_idnumber_problems() { $this->resetAfterTest(true); - $c1 = $this->getDataGenerator()->create_course(array('idnumber' => 'Taken')); + $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'sntaken', 'idnumber' => 'taken')); $c2 = $this->getDataGenerator()->create_course(); // Create with existing ID number. @@ -799,6 +840,84 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); $this->assertFalse($co->prepare()); $this->assertArrayHasKey('cannotrenameidnumberconflict', $co->get_errors()); + + // Incrementing shortname increments idnumber. + $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('shortname' => $c1->shortname, 'idnumber' => $c1->idnumber, 'summary' => 'S', 'fullname' => 'F', + 'category' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); + $this->assertTrue($co->prepare()); + $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); + $this->assertArrayHasKey('courseidnumberincremented', $co->get_statuses()); + $data = $co->get_data(); + $this->assertEquals('sntaken_2', $data['shortname']); + $this->assertEquals('taken_2', $data['idnumber']); + + // Incrementing shortname increments idnumber unless available. + $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('shortname' => $c1->shortname, 'idnumber' => 'nottaken', 'summary' => 'S', 'fullname' => 'F', + 'category' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); + $this->assertTrue($co->prepare()); + $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); + $this->assertArrayNotHasKey('courseidnumberincremented', $co->get_statuses()); + $data = $co->get_data(); + $this->assertEquals('sntaken_2', $data['shortname']); + $this->assertEquals('nottaken', $data['idnumber']); + } + + public function test_generate_shortname() { + $this->resetAfterTest(true); + + $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'taken')); + + // Generate a shortname. + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1', 'idnumber' => 'IDN'); + $importoptions = array('shortnametemplate' => '%i'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertTrue($co->prepare()); + $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses()); + + // Generate a shortname without a template. + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); + $this->assertFalse($co->prepare()); + $this->assertArrayHasKey('missingshortnamenotemplate', $co->get_errors()); + + // Generate a shortname in update mode. + $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; + $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; + $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1'); + $importoptions = array('shortnametemplate' => '%f'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertFalse($co->prepare()); + // Commented because we never get here as the course without shortname does not exist. + // $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors()); + + // Generate a shortname to a course that already exists. + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1'); + $importoptions = array('shortnametemplate' => '%f'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertFalse($co->prepare()); + $this->assertArrayHasKey('generatedshortnamealreadyinuse', $co->get_errors()); + + // Generate a shortname to a course that already exists will be incremented. + $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; + $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; + $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1'); + $importoptions = array('shortnametemplate' => '%f'); + $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); + $this->assertTrue($co->prepare()); + $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses()); + $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); } } diff --git a/admin/tool/uploadcourse/tests/helper_test.php b/admin/tool/uploadcourse/tests/helper_test.php index a61fa674d9e..f81c59f4a55 100644 --- a/admin/tool/uploadcourse/tests/helper_test.php +++ b/admin/tool/uploadcourse/tests/helper_test.php @@ -36,13 +36,19 @@ global $CFG; class tool_uploadcourse_helper_testcase extends advanced_testcase { public function test_generate_shortname() { - $data = (object) array('fullname' => 'Ah Bh Ch 01 02 03', 'idnumber' => 'ID123'); + $data = (object) array('fullname' => 'Ah bh Ch 01 02 03', 'idnumber' => 'ID123'); $this->assertSame($data->fullname, tool_uploadcourse_helper::generate_shortname($data, '%f')); $this->assertSame($data->idnumber, tool_uploadcourse_helper::generate_shortname($data, '%i')); + $this->assertSame('Ah Bh Ch', tool_uploadcourse_helper::generate_shortname($data, '%~8f')); $this->assertSame('AH BH CH', tool_uploadcourse_helper::generate_shortname($data, '%+8f')); $this->assertSame('id123', tool_uploadcourse_helper::generate_shortname($data, '%-i')); - $this->assertSame('[Ah Bh Ch] = ID123', tool_uploadcourse_helper::generate_shortname($data, '[%8f] = %i')); + $this->assertSame('[Ah bh Ch] = ID123', tool_uploadcourse_helper::generate_shortname($data, '[%8f] = %i')); + $this->assertSame('0', tool_uploadcourse_helper::generate_shortname($data, '0')); + $this->assertSame('%unknown', tool_uploadcourse_helper::generate_shortname($data, '%unknown')); + + $this->assertNull(tool_uploadcourse_helper::generate_shortname($data, '')); + $this->assertNull(tool_uploadcourse_helper::generate_shortname(array(), '%f')); } public function test_get_course_formats() { @@ -165,6 +171,12 @@ class tool_uploadcourse_helper_testcase extends advanced_testcase { $this->assertEquals($bcinfo->original_course_id, $c2->id); $this->assertEquals($bcinfo->original_course_fullname, $c2->fullname); + // Get a course that does not exist. + $errors = array(); + $dir = tool_uploadcourse_helper::get_restore_content_dir(null, 'DoesNotExist', $errors); + $this->assertFalse($dir); + $this->assertArrayHasKey('coursetorestorefromdoesnotexist', $errors); + // Cleaning content directories. $oldcfg = isset($CFG->keeptempdirectoriesonbackup) ? $CFG->keeptempdirectoriesonbackup : false; $dir = "$CFG->tempdir/backup/$dir"; diff --git a/admin/tool/uploadcourse/tests/processor_test.php b/admin/tool/uploadcourse/tests/processor_test.php index 8aee781a219..648fcc6d936 100644 --- a/admin/tool/uploadcourse/tests/processor_test.php +++ b/admin/tool/uploadcourse/tests/processor_test.php @@ -166,4 +166,60 @@ class tool_uploadcourse_processor_testcase extends advanced_testcase { $this->assertEquals('ID123: Course 1', $c->shortname); } + public function test_empty_csv() { + $this->resetAfterTest(true); + + $content = array(); + $content = implode("\n", $content); + $iid = csv_import_reader::get_new_iid('uploadcourse'); + $cir = new csv_import_reader($iid, 'uploadcourse'); + $cir->load_csv_content($content, 'utf-8', 'comma'); + $cir->init(); + + $options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW); + $this->setExpectedException('moodle_exception'); + $p = new tool_uploadcourse_processor($cir, $options, array()); + } + + public function test_not_enough_columns() { + $this->resetAfterTest(true); + + $content = array( + "shortname", + "c1", + ); + $content = implode("\n", $content); + $iid = csv_import_reader::get_new_iid('uploadcourse'); + $cir = new csv_import_reader($iid, 'uploadcourse'); + $cir->load_csv_content($content, 'utf-8', 'comma'); + $cir->init(); + + $options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW); + $this->setExpectedException('moodle_exception'); + $p = new tool_uploadcourse_processor($cir, $options, array()); + } + + public function test_preview() { + global $DB; + $this->resetAfterTest(true); + + $content = array( + "shortname,fullname,summary", + "c1,Course 1,Course 1 summary", + "c2,Course 2,Course 2 summary", + ); + $content = implode("\n", $content); + $iid = csv_import_reader::get_new_iid('uploadcourse'); + $cir = new csv_import_reader($iid, 'uploadcourse'); + $cir->load_csv_content($content, 'utf-8', 'comma'); + $cir->init(); + + $options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_ALL); + $defaults = array('category' => '1'); + + $p = new tool_uploadcourse_processor($cir, $options, $defaults); + // Nothing special to expect here, just make sure no exceptions are thrown. + $p->preview(); + } + }