| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | namespace mod_data;
 | 
        
           |  |  | 18 |   | 
        
           |  |  | 19 | use coding_exception;
 | 
        
           |  |  | 20 | use dml_exception;
 | 
        
           |  |  | 21 | use mod_data\local\importer\csv_entries_importer;
 | 
        
           |  |  | 22 | use moodle_exception;
 | 
        
           |  |  | 23 | use zip_archive;
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | /**
 | 
        
           |  |  | 26 |  * Unit tests for import.php.
 | 
        
           |  |  | 27 |  *
 | 
        
           |  |  | 28 |  * @package    mod_data
 | 
        
           |  |  | 29 |  * @category   test
 | 
        
           |  |  | 30 |  * @covers     \mod_data\local\importer\entries_importer
 | 
        
           |  |  | 31 |  * @covers     \mod_data\local\importer\csv_entries_importer
 | 
        
           |  |  | 32 |  * @copyright  2019 Tobias Reischmann
 | 
        
           |  |  | 33 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 34 |  */
 | 
        
           |  |  | 35 | final class entries_import_test extends \advanced_testcase {
 | 
        
           |  |  | 36 |   | 
        
           |  |  | 37 |     /**
 | 
        
           |  |  | 38 |      * Set up function.
 | 
        
           |  |  | 39 |      */
 | 
        
           |  |  | 40 |     protected function setUp(): void {
 | 
        
           |  |  | 41 |         parent::setUp();
 | 
        
           |  |  | 42 |   | 
        
           |  |  | 43 |         global $CFG;
 | 
        
           |  |  | 44 |         require_once($CFG->dirroot . '/mod/data/lib.php');
 | 
        
           |  |  | 45 |         require_once($CFG->dirroot . '/lib/datalib.php');
 | 
        
           |  |  | 46 |         require_once($CFG->dirroot . '/lib/csvlib.class.php');
 | 
        
           |  |  | 47 |         require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
 | 
        
           |  |  | 48 |         require_once($CFG->dirroot . '/mod/data/tests/generator/lib.php');
 | 
        
           |  |  | 49 |     }
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 |     /**
 | 
        
           |  |  | 52 |      * Get the test data.
 | 
        
           |  |  | 53 |      * In this instance we are setting up database records to be used in the unit tests.
 | 
        
           |  |  | 54 |      *
 | 
        
           |  |  | 55 |      * @return array
 | 
        
           |  |  | 56 |      */
 | 
        
           |  |  | 57 |     protected function get_test_data(): array {
 | 
        
           |  |  | 58 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 59 |   | 
        
           |  |  | 60 |         $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 | 
        
           |  |  | 61 |         $course = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 62 |         $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 | 
        
           |  |  | 63 |         $this->setUser($teacher);
 | 
        
           |  |  | 64 |         $student = $this->getDataGenerator()->create_and_enrol($course, 'student', array('username' => 'student'));
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |         $data = $generator->create_instance(array('course' => $course->id));
 | 
        
           |  |  | 67 |         $cm = get_coursemodule_from_instance('data', $data->id);
 | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 |         // Add fields.
 | 
        
           |  |  | 70 |         $fieldrecord = new \stdClass();
 | 
        
           |  |  | 71 |         $fieldrecord->name = 'ID'; // Identifier of the records for testing.
 | 
        
           |  |  | 72 |         $fieldrecord->type = 'number';
 | 
        
           |  |  | 73 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 74 |   | 
        
           |  |  | 75 |         $fieldrecord->name = 'Param2';
 | 
        
           |  |  | 76 |         $fieldrecord->type = 'text';
 | 
        
           |  |  | 77 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 |         $fieldrecord->name = 'filefield';
 | 
        
           |  |  | 80 |         $fieldrecord->type = 'file';
 | 
        
           |  |  | 81 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 82 |   | 
        
           |  |  | 83 |         $fieldrecord->name = 'picturefield';
 | 
        
           |  |  | 84 |         $fieldrecord->type = 'picture';
 | 
        
           |  |  | 85 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 86 |   | 
        
           |  |  | 87 |         return [
 | 
        
           |  |  | 88 |             'teacher' => $teacher,
 | 
        
           |  |  | 89 |             'student' => $student,
 | 
        
           |  |  | 90 |             'data' => $data,
 | 
        
           |  |  | 91 |             'cm' => $cm,
 | 
        
           |  |  | 92 |         ];
 | 
        
           |  |  | 93 |     }
 | 
        
           |  |  | 94 |   | 
        
           |  |  | 95 |     /**
 | 
        
           |  |  | 96 |      * Test uploading entries for a data instance without userdata.
 | 
        
           |  |  | 97 |      *
 | 
        
           |  |  | 98 |      * @throws dml_exception
 | 
        
           |  |  | 99 |      */
 | 
        
           |  |  | 100 |     public function test_import(): void {
 | 
        
           |  |  | 101 |         [
 | 
        
           |  |  | 102 |             'data' => $data,
 | 
        
           |  |  | 103 |             'cm' => $cm,
 | 
        
           |  |  | 104 |             'teacher' => $teacher,
 | 
        
           |  |  | 105 |         ] = $this->get_test_data();
 | 
        
           |  |  | 106 |   | 
        
           | 1441 | ariadna | 107 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import.csv'),
 | 
        
           | 1 | efrain | 108 |             'test_data_import.csv');
 | 
        
           |  |  | 109 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 110 |   | 
        
           |  |  | 111 |         // No userdata is present in the file: Fallback is to assign the uploading user as author.
 | 
        
           |  |  | 112 |         $expecteduserids = array();
 | 
        
           |  |  | 113 |         $expecteduserids[1] = $teacher->id;
 | 
        
           |  |  | 114 |         $expecteduserids[2] = $teacher->id;
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 117 |         $this->assertCount(2, $records);
 | 
        
           |  |  | 118 |         foreach ($records as $record) {
 | 
        
           |  |  | 119 |             $identifier = $record->items['ID']->content;
 | 
        
           |  |  | 120 |             $this->assertEquals($expecteduserids[$identifier], $record->userid);
 | 
        
           |  |  | 121 |         }
 | 
        
           |  |  | 122 |     }
 | 
        
           |  |  | 123 |   | 
        
           |  |  | 124 |     /**
 | 
        
           |  |  | 125 |      * Test uploading entries for a data instance with userdata.
 | 
        
           |  |  | 126 |      *
 | 
        
           |  |  | 127 |      * At least one entry has an identifiable user, which is assigned as author.
 | 
        
           |  |  | 128 |      *
 | 
        
           |  |  | 129 |      * @throws dml_exception
 | 
        
           |  |  | 130 |      */
 | 
        
           |  |  | 131 |     public function test_import_with_userdata(): void {
 | 
        
           |  |  | 132 |         [
 | 
        
           |  |  | 133 |             'data' => $data,
 | 
        
           |  |  | 134 |             'cm' => $cm,
 | 
        
           |  |  | 135 |             'teacher' => $teacher,
 | 
        
           |  |  | 136 |             'student' => $student,
 | 
        
           |  |  | 137 |         ] = $this->get_test_data();
 | 
        
           |  |  | 138 |   | 
        
           | 1441 | ariadna | 139 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_userdata.csv'),
 | 
        
           | 1 | efrain | 140 |             'test_data_import_with_userdata.csv');
 | 
        
           |  |  | 141 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |         $expecteduserids = array();
 | 
        
           |  |  | 144 |         $expecteduserids[1] = $student->id; // User student exists and is assigned as author.
 | 
        
           |  |  | 145 |         $expecteduserids[2] = $teacher->id; // User student2 does not exist. Fallback is the uploading user.
 | 
        
           |  |  | 146 |   | 
        
           |  |  | 147 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 148 |         $this->assertCount(2, $records);
 | 
        
           |  |  | 149 |         foreach ($records as $record) {
 | 
        
           |  |  | 150 |             $identifier = $record->items['ID']->content;
 | 
        
           |  |  | 151 |             $this->assertEquals($expecteduserids[$identifier], $record->userid);
 | 
        
           |  |  | 152 |         }
 | 
        
           |  |  | 153 |     }
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |     /**
 | 
        
           |  |  | 156 |      * Test uploading entries for a data instance with userdata and a defined field 'Username'.
 | 
        
           |  |  | 157 |      *
 | 
        
           |  |  | 158 |      * This should test the corner case, in which a user has defined a data fields, which has the same name
 | 
        
           |  |  | 159 |      * as the current lang string for username. In that case, the first Username entry is used for the field.
 | 
        
           |  |  | 160 |      * The second one is used to identify the author.
 | 
        
           |  |  | 161 |      *
 | 
        
           |  |  | 162 |      * @throws coding_exception
 | 
        
           |  |  | 163 |      * @throws dml_exception
 | 
        
           |  |  | 164 |      */
 | 
        
           |  |  | 165 |     public function test_import_with_field_username(): void {
 | 
        
           |  |  | 166 |         [
 | 
        
           |  |  | 167 |             'data' => $data,
 | 
        
           |  |  | 168 |             'cm' => $cm,
 | 
        
           |  |  | 169 |             'teacher' => $teacher,
 | 
        
           |  |  | 170 |             'student' => $student,
 | 
        
           |  |  | 171 |         ] = $this->get_test_data();
 | 
        
           |  |  | 172 |         $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |         // Add username field.
 | 
        
           |  |  | 175 |         $fieldrecord = new \stdClass();
 | 
        
           |  |  | 176 |         $fieldrecord->name = 'Username';
 | 
        
           |  |  | 177 |         $fieldrecord->type = 'text';
 | 
        
           |  |  | 178 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 179 |   | 
        
           | 1441 | ariadna | 180 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_field_username.csv'),
 | 
        
           | 1 | efrain | 181 |             'test_data_import_with_field_username.csv');
 | 
        
           |  |  | 182 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |         $expecteduserids = array();
 | 
        
           |  |  | 185 |         $expecteduserids[1] = $student->id; // User student exists and is assigned as author.
 | 
        
           |  |  | 186 |         $expecteduserids[2] = $teacher->id; // User student2 does not exist. Fallback is the uploading user.
 | 
        
           |  |  | 187 |         $expecteduserids[3] = $student->id; // User student exists and is assigned as author.
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 |         $expectedcontent = array();
 | 
        
           |  |  | 190 |         $expectedcontent[1] = array(
 | 
        
           |  |  | 191 |             'Username' => 'otherusername1',
 | 
        
           |  |  | 192 |             'Param2' => 'My first entry',
 | 
        
           |  |  | 193 |         );
 | 
        
           |  |  | 194 |         $expectedcontent[2] = array(
 | 
        
           |  |  | 195 |             'Username' => 'otherusername2',
 | 
        
           |  |  | 196 |             'Param2' => 'My second entry',
 | 
        
           |  |  | 197 |         );
 | 
        
           |  |  | 198 |         $expectedcontent[3] = array(
 | 
        
           |  |  | 199 |             'Username' => 'otherusername3',
 | 
        
           |  |  | 200 |             'Param2' => 'My third entry',
 | 
        
           |  |  | 201 |         );
 | 
        
           |  |  | 202 |   | 
        
           |  |  | 203 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 204 |         $this->assertCount(3, $records);
 | 
        
           |  |  | 205 |         foreach ($records as $record) {
 | 
        
           |  |  | 206 |             $identifier = $record->items['ID']->content;
 | 
        
           |  |  | 207 |             $this->assertEquals($expecteduserids[$identifier], $record->userid);
 | 
        
           |  |  | 208 |   | 
        
           |  |  | 209 |             foreach ($expectedcontent[$identifier] as $field => $value) {
 | 
        
           |  |  | 210 |                 $this->assertEquals($value, $record->items[$field]->content,
 | 
        
           |  |  | 211 |                     "The value of field \"$field\" for the record at position \"$identifier\" " .
 | 
        
           |  |  | 212 |                     "which is \"{$record->items[$field]->content}\" does not match the expected value \"$value\".");
 | 
        
           |  |  | 213 |             }
 | 
        
           |  |  | 214 |         }
 | 
        
           |  |  | 215 |     }
 | 
        
           |  |  | 216 |   | 
        
           |  |  | 217 |     /**
 | 
        
           |  |  | 218 |      * Test uploading entries for a data instance with a field 'Username' but only one occurrence in the csv file.
 | 
        
           |  |  | 219 |      *
 | 
        
           |  |  | 220 |      * This should test the corner case, in which a user has defined a data fields, which has the same name
 | 
        
           |  |  | 221 |      * as the current lang string for username. In that case, the only Username entry is used for the field.
 | 
        
           |  |  | 222 |      * The author should not be set.
 | 
        
           |  |  | 223 |      *
 | 
        
           |  |  | 224 |      * @throws coding_exception
 | 
        
           |  |  | 225 |      * @throws dml_exception
 | 
        
           |  |  | 226 |      */
 | 
        
           |  |  | 227 |     public function test_import_with_field_username_without_userdata(): void {
 | 
        
           |  |  | 228 |         [
 | 
        
           |  |  | 229 |             'data' => $data,
 | 
        
           |  |  | 230 |             'cm' => $cm,
 | 
        
           |  |  | 231 |             'teacher' => $teacher,
 | 
        
           |  |  | 232 |             'student' => $student,
 | 
        
           |  |  | 233 |         ] = $this->get_test_data();
 | 
        
           |  |  | 234 |         $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 | 
        
           |  |  | 235 |   | 
        
           |  |  | 236 |         // Add username field.
 | 
        
           |  |  | 237 |         $fieldrecord = new \stdClass();
 | 
        
           |  |  | 238 |         $fieldrecord->name = 'Username';
 | 
        
           |  |  | 239 |         $fieldrecord->type = 'text';
 | 
        
           |  |  | 240 |         $generator->create_field($fieldrecord, $data);
 | 
        
           |  |  | 241 |   | 
        
           | 1441 | ariadna | 242 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_userdata.csv'),
 | 
        
           | 1 | efrain | 243 |             'test_data_import_with_userdata.csv');
 | 
        
           |  |  | 244 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 245 |   | 
        
           |  |  | 246 |         // No userdata is present in the file: Fallback is to assign the uploading user as author.
 | 
        
           |  |  | 247 |         $expecteduserids = array();
 | 
        
           |  |  | 248 |         $expecteduserids[1] = $teacher->id;
 | 
        
           |  |  | 249 |         $expecteduserids[2] = $teacher->id;
 | 
        
           |  |  | 250 |   | 
        
           |  |  | 251 |         $expectedcontent = array();
 | 
        
           |  |  | 252 |         $expectedcontent[1] = array(
 | 
        
           |  |  | 253 |             'Username' => 'student',
 | 
        
           |  |  | 254 |             'Param2' => 'My first entry',
 | 
        
           |  |  | 255 |         );
 | 
        
           |  |  | 256 |         $expectedcontent[2] = array(
 | 
        
           |  |  | 257 |             'Username' => 'student2',
 | 
        
           |  |  | 258 |             'Param2' => 'My second entry',
 | 
        
           |  |  | 259 |         );
 | 
        
           |  |  | 260 |   | 
        
           |  |  | 261 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 262 |         $this->assertCount(2, $records);
 | 
        
           |  |  | 263 |         foreach ($records as $record) {
 | 
        
           |  |  | 264 |             $identifier = $record->items['ID']->content;
 | 
        
           |  |  | 265 |             $this->assertEquals($expecteduserids[$identifier], $record->userid);
 | 
        
           |  |  | 266 |   | 
        
           |  |  | 267 |             foreach ($expectedcontent[$identifier] as $field => $value) {
 | 
        
           |  |  | 268 |                 $this->assertEquals($value, $record->items[$field]->content,
 | 
        
           |  |  | 269 |                     "The value of field \"$field\" for the record at position \"$identifier\" " .
 | 
        
           |  |  | 270 |                     "which is \"{$record->items[$field]->content}\" does not match the expected value \"$value\".");
 | 
        
           |  |  | 271 |             }
 | 
        
           |  |  | 272 |         }
 | 
        
           |  |  | 273 |     }
 | 
        
           |  |  | 274 |   | 
        
           |  |  | 275 |     /**
 | 
        
           |  |  | 276 |      * Data provider for {@see test_import_without_approved}
 | 
        
           |  |  | 277 |      *
 | 
        
           |  |  | 278 |      * @return array[]
 | 
        
           |  |  | 279 |      */
 | 
        
           |  |  | 280 |     public static function import_without_approved_provider(): array {
 | 
        
           |  |  | 281 |         return [
 | 
        
           |  |  | 282 |             'Teacher can approve entries' => ['teacher', [1, 1]],
 | 
        
           |  |  | 283 |             'Student cannot approve entries' => ['student', [0, 0]],
 | 
        
           |  |  | 284 |         ];
 | 
        
           |  |  | 285 |     }
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |     /**
 | 
        
           |  |  | 288 |      * Test importing file without approved status column
 | 
        
           |  |  | 289 |      *
 | 
        
           |  |  | 290 |      * @param string $user
 | 
        
           |  |  | 291 |      * @param int[] $expected
 | 
        
           |  |  | 292 |      *
 | 
        
           |  |  | 293 |      * @dataProvider import_without_approved_provider
 | 
        
           |  |  | 294 |      */
 | 
        
           |  |  | 295 |     public function test_import_without_approved(string $user, array $expected): void {
 | 
        
           |  |  | 296 |         $testdata = $this->get_test_data();
 | 
        
           |  |  | 297 |         ['data' => $data, 'cm' => $cm] = $testdata;
 | 
        
           |  |  | 298 |   | 
        
           |  |  | 299 |         $this->setUser($testdata[$user]);
 | 
        
           |  |  | 300 |   | 
        
           | 1441 | ariadna | 301 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import.csv'), 'test_data_import.csv');
 | 
        
           | 1 | efrain | 302 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 305 |         $this->assertEquals($expected, array_column($records, 'approved'));
 | 
        
           |  |  | 306 |     }
 | 
        
           |  |  | 307 |   | 
        
           |  |  | 308 |     /**
 | 
        
           |  |  | 309 |      * Data provider for {@see test_import_with_approved}
 | 
        
           |  |  | 310 |      *
 | 
        
           |  |  | 311 |      * @return array[]
 | 
        
           |  |  | 312 |      */
 | 
        
           |  |  | 313 |     public static function import_with_approved_provider(): array {
 | 
        
           |  |  | 314 |         return [
 | 
        
           |  |  | 315 |             'Teacher can approve entries' => ['teacher', [1, 0]],
 | 
        
           |  |  | 316 |             'Student cannot approve entries' => ['student', [0, 0]],
 | 
        
           |  |  | 317 |         ];
 | 
        
           |  |  | 318 |     }
 | 
        
           |  |  | 319 |   | 
        
           |  |  | 320 |     /**
 | 
        
           |  |  | 321 |      * Test importing file with approved status column
 | 
        
           |  |  | 322 |      *
 | 
        
           |  |  | 323 |      * @param string $user
 | 
        
           |  |  | 324 |      * @param int[] $expected
 | 
        
           |  |  | 325 |      *
 | 
        
           |  |  | 326 |      * @dataProvider import_with_approved_provider
 | 
        
           |  |  | 327 |      */
 | 
        
           |  |  | 328 |     public function test_import_with_approved(string $user, array $expected): void {
 | 
        
           |  |  | 329 |         $testdata = $this->get_test_data();
 | 
        
           |  |  | 330 |         ['data' => $data, 'cm' => $cm] = $testdata;
 | 
        
           |  |  | 331 |   | 
        
           |  |  | 332 |         $this->setUser($testdata[$user]);
 | 
        
           |  |  | 333 |   | 
        
           | 1441 | ariadna | 334 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_approved.csv'),
 | 
        
           | 1 | efrain | 335 |             'test_data_import_with_approved.csv');
 | 
        
           |  |  | 336 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 337 |   | 
        
           |  |  | 338 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 339 |         $this->assertEquals($expected, array_column($records, 'approved'));
 | 
        
           |  |  | 340 |     }
 | 
        
           |  |  | 341 |   | 
        
           |  |  | 342 |     /**
 | 
        
           |  |  | 343 |      * Tests the import including files from a zip archive.
 | 
        
           |  |  | 344 |      */
 | 
        
           |  |  | 345 |     public function test_import_with_files(): void {
 | 
        
           |  |  | 346 |         [
 | 
        
           |  |  | 347 |             'data' => $data,
 | 
        
           |  |  | 348 |             'cm' => $cm,
 | 
        
           |  |  | 349 |         ] = $this->get_test_data();
 | 
        
           |  |  | 350 |   | 
        
           | 1441 | ariadna | 351 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_files.zip'),
 | 
        
           | 1 | efrain | 352 |             'test_data_import_with_files.zip');
 | 
        
           |  |  | 353 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 356 |         $ziparchive = new zip_archive();
 | 
        
           | 1441 | ariadna | 357 |         $ziparchive->open(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_files.zip'));
 | 
        
           | 1 | efrain | 358 |   | 
        
           |  |  | 359 |         $importedcontent = array_values($records)[0]->items;
 | 
        
           |  |  | 360 |         $this->assertEquals(17, $importedcontent['ID']->content);
 | 
        
           |  |  | 361 |         $this->assertEquals('samplefile.png', $importedcontent['filefield']->content);
 | 
        
           |  |  | 362 |         $this->assertEquals('samplepicture.png', $importedcontent['picturefield']->content);
 | 
        
           |  |  | 363 |   | 
        
           |  |  | 364 |         // We now check if content of imported file from zip content is identical to the content of the file
 | 
        
           |  |  | 365 |         // stored in the mod_data record in the field 'filefield'.
 | 
        
           |  |  | 366 |         $fileindex = array_values(array_map(fn($file) => $file->index,
 | 
        
           |  |  | 367 |             array_filter($ziparchive->list_files(), fn($file) => $file->pathname === 'files/samplefile.png')))[0];
 | 
        
           |  |  | 368 |         $filestream = $ziparchive->get_stream($fileindex);
 | 
        
           |  |  | 369 |         $filefield = data_get_field_from_name('filefield', $data);
 | 
        
           |  |  | 370 |         $filefieldfilecontent = fread($filestream, $ziparchive->get_info($fileindex)->size);
 | 
        
           |  |  | 371 |         $this->assertEquals($filefield->get_file(array_keys($records)[0])->get_content(),
 | 
        
           |  |  | 372 |             $filefieldfilecontent);
 | 
        
           |  |  | 373 |         fclose($filestream);
 | 
        
           |  |  | 374 |   | 
        
           |  |  | 375 |         // We now check if content of imported picture from zip content is identical to the content of the picture file
 | 
        
           |  |  | 376 |         // stored in the mod_data record in the field 'picturefield'.
 | 
        
           |  |  | 377 |         $fileindex = array_values(array_map(fn($file) => $file->index,
 | 
        
           |  |  | 378 |             array_filter($ziparchive->list_files(), fn($file) => $file->pathname === 'files/samplepicture.png')))[0];
 | 
        
           |  |  | 379 |         $filestream = $ziparchive->get_stream($fileindex);
 | 
        
           |  |  | 380 |         $filefield = data_get_field_from_name('picturefield', $data);
 | 
        
           |  |  | 381 |         $filefieldfilecontent = fread($filestream, $ziparchive->get_info($fileindex)->size);
 | 
        
           |  |  | 382 |         $this->assertEquals($filefield->get_file(array_keys($records)[0])->get_content(),
 | 
        
           |  |  | 383 |             $filefieldfilecontent);
 | 
        
           |  |  | 384 |         fclose($filestream);
 | 
        
           |  |  | 385 |         $this->assertCount(1, $importer->get_added_records_messages());
 | 
        
           |  |  | 386 |         $ziparchive->close();
 | 
        
           |  |  | 387 |     }
 | 
        
           |  |  | 388 |   | 
        
           |  |  | 389 |     /**
 | 
        
           |  |  | 390 |      * Tests the import including files from a zip archive.
 | 
        
           |  |  | 391 |      */
 | 
        
           |  |  | 392 |     public function test_import_with_files_missing_file(): void {
 | 
        
           |  |  | 393 |         [
 | 
        
           |  |  | 394 |             'data' => $data,
 | 
        
           |  |  | 395 |             'cm' => $cm,
 | 
        
           |  |  | 396 |         ] = $this->get_test_data();
 | 
        
           |  |  | 397 |   | 
        
           | 1441 | ariadna | 398 |         $importer = new csv_entries_importer(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_files_missing_file.zip'),
 | 
        
           | 1 | efrain | 399 |             'test_data_import_with_files_missing_file.zip');
 | 
        
           |  |  | 400 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 401 |   | 
        
           |  |  | 402 |         $records = $this->get_data_records($data->id);
 | 
        
           |  |  | 403 |         $ziparchive = new zip_archive();
 | 
        
           | 1441 | ariadna | 404 |         $ziparchive->open(self::get_fixture_path(__NAMESPACE__, 'test_data_import_with_files_missing_file.zip'));
 | 
        
           | 1 | efrain | 405 |   | 
        
           |  |  | 406 |         $importedcontent = array_values($records)[0]->items;
 | 
        
           |  |  | 407 |         $this->assertEquals(17, $importedcontent['ID']->content);
 | 
        
           |  |  | 408 |         $this->assertFalse(isset($importedcontent['filefield']));
 | 
        
           |  |  | 409 |         $this->assertEquals('samplepicture.png', $importedcontent['picturefield']->content);
 | 
        
           |  |  | 410 |         $this->assertCount(1, $importer->get_added_records_messages());
 | 
        
           |  |  | 411 |         $ziparchive->close();
 | 
        
           |  |  | 412 |     }
 | 
        
           |  |  | 413 |   | 
        
           |  |  | 414 |     /**
 | 
        
           |  |  | 415 |      * Returns the records of the data instance.
 | 
        
           |  |  | 416 |      *
 | 
        
           |  |  | 417 |      * Each records has an item entry, which contains all fields associated with this item.
 | 
        
           |  |  | 418 |      * Each fields has the parameters name, type and content.
 | 
        
           |  |  | 419 |      *
 | 
        
           |  |  | 420 |      * @param int $dataid Id of the data instance.
 | 
        
           |  |  | 421 |      * @return array The records of the data instance.
 | 
        
           |  |  | 422 |      * @throws dml_exception
 | 
        
           |  |  | 423 |      */
 | 
        
           |  |  | 424 |     private function get_data_records(int $dataid): array {
 | 
        
           |  |  | 425 |         global $DB;
 | 
        
           |  |  | 426 |   | 
        
           |  |  | 427 |         $records = $DB->get_records('data_records', ['dataid' => $dataid]);
 | 
        
           |  |  | 428 |         foreach ($records as $record) {
 | 
        
           |  |  | 429 |             $sql = 'SELECT f.name, f.type, con.content FROM
 | 
        
           |  |  | 430 |                 {data_content} con JOIN {data_fields} f ON con.fieldid = f.id
 | 
        
           |  |  | 431 |                 WHERE con.recordid = :recordid';
 | 
        
           |  |  | 432 |             $items = $DB->get_records_sql($sql, array('recordid' => $record->id));
 | 
        
           |  |  | 433 |             $record->items = $items;
 | 
        
           |  |  | 434 |         }
 | 
        
           |  |  | 435 |         return $records;
 | 
        
           |  |  | 436 |     }
 | 
        
           |  |  | 437 |   | 
        
           |  |  | 438 |     /**
 | 
        
           |  |  | 439 |      * Tests if the amount of imported records is counted properly.
 | 
        
           |  |  | 440 |      *
 | 
        
           |  |  | 441 |      * @dataProvider get_added_record_messages_provider
 | 
        
           |  |  | 442 |      * @param string $datafilecontent the content of the datafile to test as string
 | 
        
           |  |  | 443 |      * @param int $expectedcount the expected count of messages depending on the datafile content
 | 
        
           |  |  | 444 |      */
 | 
        
           |  |  | 445 |     public function test_get_added_record_messages(string $datafilecontent, int $expectedcount): void {
 | 
        
           |  |  | 446 |         [
 | 
        
           |  |  | 447 |             'data' => $data,
 | 
        
           |  |  | 448 |             'cm' => $cm,
 | 
        
           |  |  | 449 |         ] = $this->get_test_data();
 | 
        
           |  |  | 450 |   | 
        
           |  |  | 451 |         // First we need to create the zip file from the provided data.
 | 
        
           |  |  | 452 |         $tmpdir = make_request_directory();
 | 
        
           |  |  | 453 |         $datafile = $tmpdir . '/entries_import_test_datafile_tmp_' . time() . '.csv';
 | 
        
           |  |  | 454 |         file_put_contents($datafile, $datafilecontent);
 | 
        
           |  |  | 455 |   | 
        
           |  |  | 456 |         $importer = new csv_entries_importer($datafile, 'testdatafile.csv');
 | 
        
           |  |  | 457 |         $importer->import_csv($cm, $data, 'UTF-8', 'comma');
 | 
        
           |  |  | 458 |         $this->assertEquals($expectedcount, count($importer->get_added_records_messages()));
 | 
        
           |  |  | 459 |     }
 | 
        
           |  |  | 460 |   | 
        
           |  |  | 461 |     /**
 | 
        
           |  |  | 462 |      * Data provider method for self::test_get_added_record_messages.
 | 
        
           |  |  | 463 |      *
 | 
        
           |  |  | 464 |      * @return array data for testing
 | 
        
           |  |  | 465 |      */
 | 
        
           | 1441 | ariadna | 466 |     public static function get_added_record_messages_provider(): array {
 | 
        
           | 1 | efrain | 467 |         return [
 | 
        
           |  |  | 468 |             'only header' => [
 | 
        
           |  |  | 469 |                 'datafilecontent' => 'ID,Param2,filefield,picturefield' . PHP_EOL,
 | 
        
           |  |  | 470 |                 'expectedcount' => 0 // One line is being assumed to be the header.
 | 
        
           |  |  | 471 |             ],
 | 
        
           |  |  | 472 |             'one record' => [
 | 
        
           |  |  | 473 |                 'datafilecontent' => 'ID,Param2,filefield,picturefield' . PHP_EOL
 | 
        
           |  |  | 474 |                     . '5,"some short text",testfilename.pdf,testpicture.png',
 | 
        
           |  |  | 475 |                 'expectedcount' => 1
 | 
        
           |  |  | 476 |             ],
 | 
        
           |  |  | 477 |             'two records' => [
 | 
        
           |  |  | 478 |                 'datafilecontent' => 'ID,Param2,filefield,picturefield' . PHP_EOL
 | 
        
           |  |  | 479 |                     . '5,"some short text",testfilename.pdf,testpicture.png' . PHP_EOL
 | 
        
           |  |  | 480 |                     . '3,"other text",testfilename2.pdf,testpicture2.png',
 | 
        
           |  |  | 481 |                 'expectedcount' => 2
 | 
        
           |  |  | 482 |             ],
 | 
        
           |  |  | 483 |         ];
 | 
        
           |  |  | 484 |     }
 | 
        
           |  |  | 485 | }
 |