|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * This provides SimpleTests for the core file handling functionality. |
|
6 * These include FileValidateTest and FileSaveTest. |
|
7 */ |
|
8 |
|
9 /** |
|
10 * Helper validator that returns the $errors parameter. |
|
11 */ |
|
12 function file_test_validator($file, $errors) { |
|
13 return $errors; |
|
14 } |
|
15 |
|
16 /** |
|
17 * Helper function for testing file_scan_directory(). |
|
18 * |
|
19 * Each time the function is called the file is stored in a static variable. |
|
20 * When the function is called with no $filepath parameter, the results are |
|
21 * returned. |
|
22 * |
|
23 * @param $filepath |
|
24 * File path |
|
25 * @return |
|
26 * If $filepath is NULL, an array of all previous $filepath parameters |
|
27 */ |
|
28 function file_test_file_scan_callback($filepath = NULL) { |
|
29 $files = &drupal_static(__FUNCTION__, array()); |
|
30 if (isset($filepath)) { |
|
31 $files[] = $filepath; |
|
32 } |
|
33 else { |
|
34 return $files; |
|
35 } |
|
36 } |
|
37 |
|
38 /** |
|
39 * Reset static variables used by file_test_file_scan_callback(). |
|
40 */ |
|
41 function file_test_file_scan_callback_reset() { |
|
42 drupal_static_reset('file_test_file_scan_callback'); |
|
43 } |
|
44 |
|
45 /** |
|
46 * Base class for file tests that adds some additional file specific |
|
47 * assertions and helper functions. |
|
48 */ |
|
49 class FileTestCase extends DrupalWebTestCase { |
|
50 /** |
|
51 * Check that two files have the same values for all fields other than the |
|
52 * timestamp. |
|
53 * |
|
54 * @param $before |
|
55 * File object to compare. |
|
56 * @param $after |
|
57 * File object to compare. |
|
58 */ |
|
59 function assertFileUnchanged($before, $after) { |
|
60 $this->assertEqual($before->fid, $after->fid, format_string('File id is the same: %file1 == %file2.', array('%file1' => $before->fid, '%file2' => $after->fid)), 'File unchanged'); |
|
61 $this->assertEqual($before->uid, $after->uid, format_string('File owner is the same: %file1 == %file2.', array('%file1' => $before->uid, '%file2' => $after->uid)), 'File unchanged'); |
|
62 $this->assertEqual($before->filename, $after->filename, format_string('File name is the same: %file1 == %file2.', array('%file1' => $before->filename, '%file2' => $after->filename)), 'File unchanged'); |
|
63 $this->assertEqual($before->uri, $after->uri, format_string('File path is the same: %file1 == %file2.', array('%file1' => $before->uri, '%file2' => $after->uri)), 'File unchanged'); |
|
64 $this->assertEqual($before->filemime, $after->filemime, format_string('File MIME type is the same: %file1 == %file2.', array('%file1' => $before->filemime, '%file2' => $after->filemime)), 'File unchanged'); |
|
65 $this->assertEqual($before->filesize, $after->filesize, format_string('File size is the same: %file1 == %file2.', array('%file1' => $before->filesize, '%file2' => $after->filesize)), 'File unchanged'); |
|
66 $this->assertEqual($before->status, $after->status, format_string('File status is the same: %file1 == %file2.', array('%file1' => $before->status, '%file2' => $after->status)), 'File unchanged'); |
|
67 } |
|
68 |
|
69 /** |
|
70 * Check that two files are not the same by comparing the fid and filepath. |
|
71 * |
|
72 * @param $file1 |
|
73 * File object to compare. |
|
74 * @param $file2 |
|
75 * File object to compare. |
|
76 */ |
|
77 function assertDifferentFile($file1, $file2) { |
|
78 $this->assertNotEqual($file1->fid, $file2->fid, format_string('Files have different ids: %file1 != %file2.', array('%file1' => $file1->fid, '%file2' => $file2->fid)), 'Different file'); |
|
79 $this->assertNotEqual($file1->uri, $file2->uri, format_string('Files have different paths: %file1 != %file2.', array('%file1' => $file1->uri, '%file2' => $file2->uri)), 'Different file'); |
|
80 } |
|
81 |
|
82 /** |
|
83 * Check that two files are the same by comparing the fid and filepath. |
|
84 * |
|
85 * @param $file1 |
|
86 * File object to compare. |
|
87 * @param $file2 |
|
88 * File object to compare. |
|
89 */ |
|
90 function assertSameFile($file1, $file2) { |
|
91 $this->assertEqual($file1->fid, $file2->fid, format_string('Files have the same ids: %file1 == %file2.', array('%file1' => $file1->fid, '%file2-fid' => $file2->fid)), 'Same file'); |
|
92 $this->assertEqual($file1->uri, $file2->uri, format_string('Files have the same path: %file1 == %file2.', array('%file1' => $file1->uri, '%file2' => $file2->uri)), 'Same file'); |
|
93 } |
|
94 |
|
95 /** |
|
96 * Helper function to test the permissions of a file. |
|
97 * |
|
98 * @param $filepath |
|
99 * String file path. |
|
100 * @param $expected_mode |
|
101 * Octal integer like 0664 or 0777. |
|
102 * @param $message |
|
103 * Optional message. |
|
104 */ |
|
105 function assertFilePermissions($filepath, $expected_mode, $message = NULL) { |
|
106 // Clear out PHP's file stat cache to be sure we see the current value. |
|
107 clearstatcache(); |
|
108 |
|
109 // Mask out all but the last three octets. |
|
110 $actual_mode = fileperms($filepath) & 0777; |
|
111 |
|
112 // PHP on Windows has limited support for file permissions. Usually each of |
|
113 // "user", "group" and "other" use one octal digit (3 bits) to represent the |
|
114 // read/write/execute bits. On Windows, chmod() ignores the "group" and |
|
115 // "other" bits, and fileperms() returns the "user" bits in all three |
|
116 // positions. $expected_mode is updated to reflect this. |
|
117 if (substr(PHP_OS, 0, 3) == 'WIN') { |
|
118 // Reset the "group" and "other" bits. |
|
119 $expected_mode = $expected_mode & 0700; |
|
120 // Shift the "user" bits to the "group" and "other" positions also. |
|
121 $expected_mode = $expected_mode | $expected_mode >> 3 | $expected_mode >> 6; |
|
122 } |
|
123 |
|
124 if (!isset($message)) { |
|
125 $message = t('Expected file permission to be %expected, actually were %actual.', array('%actual' => decoct($actual_mode), '%expected' => decoct($expected_mode))); |
|
126 } |
|
127 $this->assertEqual($actual_mode, $expected_mode, $message); |
|
128 } |
|
129 |
|
130 /** |
|
131 * Helper function to test the permissions of a directory. |
|
132 * |
|
133 * @param $directory |
|
134 * String directory path. |
|
135 * @param $expected_mode |
|
136 * Octal integer like 0664 or 0777. |
|
137 * @param $message |
|
138 * Optional message. |
|
139 */ |
|
140 function assertDirectoryPermissions($directory, $expected_mode, $message = NULL) { |
|
141 // Clear out PHP's file stat cache to be sure we see the current value. |
|
142 clearstatcache(); |
|
143 |
|
144 // Mask out all but the last three octets. |
|
145 $actual_mode = fileperms($directory) & 0777; |
|
146 |
|
147 // PHP on Windows has limited support for file permissions. Usually each of |
|
148 // "user", "group" and "other" use one octal digit (3 bits) to represent the |
|
149 // read/write/execute bits. On Windows, chmod() ignores the "group" and |
|
150 // "other" bits, and fileperms() returns the "user" bits in all three |
|
151 // positions. $expected_mode is updated to reflect this. |
|
152 if (substr(PHP_OS, 0, 3) == 'WIN') { |
|
153 // Reset the "group" and "other" bits. |
|
154 $expected_mode = $expected_mode & 0700; |
|
155 // Shift the "user" bits to the "group" and "other" positions also. |
|
156 $expected_mode = $expected_mode | $expected_mode >> 3 | $expected_mode >> 6; |
|
157 } |
|
158 |
|
159 if (!isset($message)) { |
|
160 $message = t('Expected directory permission to be %expected, actually were %actual.', array('%actual' => decoct($actual_mode), '%expected' => decoct($expected_mode))); |
|
161 } |
|
162 $this->assertEqual($actual_mode, $expected_mode, $message); |
|
163 } |
|
164 |
|
165 /** |
|
166 * Create a directory and assert it exists. |
|
167 * |
|
168 * @param $path |
|
169 * Optional string with a directory path. If none is provided, a random |
|
170 * name in the site's files directory will be used. |
|
171 * @return |
|
172 * The path to the directory. |
|
173 */ |
|
174 function createDirectory($path = NULL) { |
|
175 // A directory to operate on. |
|
176 if (!isset($path)) { |
|
177 $path = file_default_scheme() . '://' . $this->randomName(); |
|
178 } |
|
179 $this->assertTrue(drupal_mkdir($path) && is_dir($path), 'Directory was created successfully.'); |
|
180 return $path; |
|
181 } |
|
182 |
|
183 /** |
|
184 * Create a file and save it to the files table and assert that it occurs |
|
185 * correctly. |
|
186 * |
|
187 * @param $filepath |
|
188 * Optional string specifying the file path. If none is provided then a |
|
189 * randomly named file will be created in the site's files directory. |
|
190 * @param $contents |
|
191 * Optional contents to save into the file. If a NULL value is provided an |
|
192 * arbitrary string will be used. |
|
193 * @param $scheme |
|
194 * Optional string indicating the stream scheme to use. Drupal core includes |
|
195 * public, private, and temporary. The public wrapper is the default. |
|
196 * @return |
|
197 * File object. |
|
198 */ |
|
199 function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) { |
|
200 if (!isset($filepath)) { |
|
201 // Prefix with non-latin characters to ensure that all file-related |
|
202 // tests work with international filenames. |
|
203 $filepath = 'Файл для тестирования ' . $this->randomName(); |
|
204 } |
|
205 if (!isset($scheme)) { |
|
206 $scheme = file_default_scheme(); |
|
207 } |
|
208 $filepath = $scheme . '://' . $filepath; |
|
209 |
|
210 if (!isset($contents)) { |
|
211 $contents = "file_put_contents() doesn't seem to appreciate empty strings so let's put in some data."; |
|
212 } |
|
213 |
|
214 file_put_contents($filepath, $contents); |
|
215 $this->assertTrue(is_file($filepath), 'The test file exists on the disk.', 'Create test file'); |
|
216 |
|
217 $file = new stdClass(); |
|
218 $file->uri = $filepath; |
|
219 $file->filename = drupal_basename($file->uri); |
|
220 $file->filemime = 'text/plain'; |
|
221 $file->uid = 1; |
|
222 $file->timestamp = REQUEST_TIME; |
|
223 $file->filesize = filesize($file->uri); |
|
224 $file->status = 0; |
|
225 // Write the record directly rather than calling file_save() so we don't |
|
226 // invoke the hooks. |
|
227 $this->assertNotIdentical(drupal_write_record('file_managed', $file), FALSE, 'The file was added to the database.', 'Create test file'); |
|
228 |
|
229 return $file; |
|
230 } |
|
231 } |
|
232 |
|
233 /** |
|
234 * Base class for file tests that use the file_test module to test uploads and |
|
235 * hooks. |
|
236 */ |
|
237 class FileHookTestCase extends FileTestCase { |
|
238 function setUp() { |
|
239 // Install file_test module |
|
240 parent::setUp('file_test'); |
|
241 // Clear out any hook calls. |
|
242 file_test_reset(); |
|
243 } |
|
244 |
|
245 /** |
|
246 * Assert that all of the specified hook_file_* hooks were called once, other |
|
247 * values result in failure. |
|
248 * |
|
249 * @param $expected |
|
250 * Array with string containing with the hook name, e.g. 'load', 'save', |
|
251 * 'insert', etc. |
|
252 */ |
|
253 function assertFileHooksCalled($expected) { |
|
254 // Determine which hooks were called. |
|
255 $actual = array_keys(array_filter(file_test_get_all_calls())); |
|
256 |
|
257 // Determine if there were any expected that were not called. |
|
258 $uncalled = array_diff($expected, $actual); |
|
259 if (count($uncalled)) { |
|
260 $this->assertTrue(FALSE, format_string('Expected hooks %expected to be called but %uncalled was not called.', array('%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled)))); |
|
261 } |
|
262 else { |
|
263 $this->assertTrue(TRUE, format_string('All the expected hooks were called: %expected', array('%expected' => empty($expected) ? t('(none)') : implode(', ', $expected)))); |
|
264 } |
|
265 |
|
266 // Determine if there were any unexpected calls. |
|
267 $unexpected = array_diff($actual, $expected); |
|
268 if (count($unexpected)) { |
|
269 $this->assertTrue(FALSE, format_string('Unexpected hooks were called: %unexpected.', array('%unexpected' => empty($unexpected) ? t('(none)') : implode(', ', $unexpected)))); |
|
270 } |
|
271 else { |
|
272 $this->assertTrue(TRUE, 'No unexpected hooks were called.'); |
|
273 } |
|
274 } |
|
275 |
|
276 /** |
|
277 * Assert that a hook_file_* hook was called a certain number of times. |
|
278 * |
|
279 * @param $hook |
|
280 * String with the hook name, e.g. 'load', 'save', 'insert', etc. |
|
281 * @param $expected_count |
|
282 * Optional integer count. |
|
283 * @param $message |
|
284 * Optional translated string message. |
|
285 */ |
|
286 function assertFileHookCalled($hook, $expected_count = 1, $message = NULL) { |
|
287 $actual_count = count(file_test_get_calls($hook)); |
|
288 |
|
289 if (!isset($message)) { |
|
290 if ($actual_count == $expected_count) { |
|
291 $message = format_string('hook_file_@name was called correctly.', array('@name' => $hook)); |
|
292 } |
|
293 elseif ($expected_count == 0) { |
|
294 $message = format_plural($actual_count, 'hook_file_@name was not expected to be called but was actually called once.', 'hook_file_@name was not expected to be called but was actually called @count times.', array('@name' => $hook, '@count' => $actual_count)); |
|
295 } |
|
296 else { |
|
297 $message = format_string('hook_file_@name was expected to be called %expected times but was called %actual times.', array('@name' => $hook, '%expected' => $expected_count, '%actual' => $actual_count)); |
|
298 } |
|
299 } |
|
300 $this->assertEqual($actual_count, $expected_count, $message); |
|
301 } |
|
302 } |
|
303 |
|
304 |
|
305 /** |
|
306 * This will run tests against the file_space_used() function. |
|
307 */ |
|
308 class FileSpaceUsedTest extends FileTestCase { |
|
309 public static function getInfo() { |
|
310 return array( |
|
311 'name' => 'File space used tests', |
|
312 'description' => 'Tests the file_space_used() function.', |
|
313 'group' => 'File API', |
|
314 ); |
|
315 } |
|
316 |
|
317 function setUp() { |
|
318 parent::setUp(); |
|
319 |
|
320 // Create records for a couple of users with different sizes. |
|
321 $file = array('uid' => 2, 'uri' => 'public://example1.txt', 'filesize' => 50, 'status' => FILE_STATUS_PERMANENT); |
|
322 drupal_write_record('file_managed', $file); |
|
323 $file = array('uid' => 2, 'uri' => 'public://example2.txt', 'filesize' => 20, 'status' => FILE_STATUS_PERMANENT); |
|
324 drupal_write_record('file_managed', $file); |
|
325 $file = array('uid' => 3, 'uri' => 'public://example3.txt', 'filesize' => 100, 'status' => FILE_STATUS_PERMANENT); |
|
326 drupal_write_record('file_managed', $file); |
|
327 $file = array('uid' => 3, 'uri' => 'public://example4.txt', 'filesize' => 200, 'status' => FILE_STATUS_PERMANENT); |
|
328 drupal_write_record('file_managed', $file); |
|
329 |
|
330 // Now create some non-permanent files. |
|
331 $file = array('uid' => 2, 'uri' => 'public://example5.txt', 'filesize' => 1, 'status' => 0); |
|
332 drupal_write_record('file_managed', $file); |
|
333 $file = array('uid' => 3, 'uri' => 'public://example6.txt', 'filesize' => 3, 'status' => 0); |
|
334 drupal_write_record('file_managed', $file); |
|
335 } |
|
336 |
|
337 /** |
|
338 * Test different users with the default status. |
|
339 */ |
|
340 function testFileSpaceUsed() { |
|
341 // Test different users with default status. |
|
342 $this->assertEqual(file_space_used(2), 70); |
|
343 $this->assertEqual(file_space_used(3), 300); |
|
344 $this->assertEqual(file_space_used(), 370); |
|
345 |
|
346 // Test the status fields |
|
347 $this->assertEqual(file_space_used(NULL, 0), 4); |
|
348 $this->assertEqual(file_space_used(NULL, FILE_STATUS_PERMANENT), 370); |
|
349 |
|
350 // Test both the user and status. |
|
351 $this->assertEqual(file_space_used(1, 0), 0); |
|
352 $this->assertEqual(file_space_used(1, FILE_STATUS_PERMANENT), 0); |
|
353 $this->assertEqual(file_space_used(2, 0), 1); |
|
354 $this->assertEqual(file_space_used(2, FILE_STATUS_PERMANENT), 70); |
|
355 $this->assertEqual(file_space_used(3, 0), 3); |
|
356 $this->assertEqual(file_space_used(3, FILE_STATUS_PERMANENT), 300); |
|
357 } |
|
358 } |
|
359 |
|
360 /** |
|
361 * This will run tests against the file validation functions (file_validate_*). |
|
362 */ |
|
363 class FileValidatorTest extends DrupalWebTestCase { |
|
364 public static function getInfo() { |
|
365 return array( |
|
366 'name' => 'File validator tests', |
|
367 'description' => 'Tests the functions used to validate uploaded files.', |
|
368 'group' => 'File API', |
|
369 ); |
|
370 } |
|
371 |
|
372 function setUp() { |
|
373 parent::setUp(); |
|
374 |
|
375 $this->image = new stdClass(); |
|
376 $this->image->uri = 'misc/druplicon.png'; |
|
377 $this->image->filename = drupal_basename($this->image->uri); |
|
378 |
|
379 $this->non_image = new stdClass(); |
|
380 $this->non_image->uri = 'misc/jquery.js'; |
|
381 $this->non_image->filename = drupal_basename($this->non_image->uri); |
|
382 } |
|
383 |
|
384 /** |
|
385 * Test the file_validate_extensions() function. |
|
386 */ |
|
387 function testFileValidateExtensions() { |
|
388 $file = new stdClass(); |
|
389 $file->filename = 'asdf.txt'; |
|
390 $errors = file_validate_extensions($file, 'asdf txt pork'); |
|
391 $this->assertEqual(count($errors), 0, 'Valid extension accepted.', 'File'); |
|
392 |
|
393 $file->filename = 'asdf.txt'; |
|
394 $errors = file_validate_extensions($file, 'exe png'); |
|
395 $this->assertEqual(count($errors), 1, 'Invalid extension blocked.', 'File'); |
|
396 } |
|
397 |
|
398 /** |
|
399 * This ensures a specific file is actually an image. |
|
400 */ |
|
401 function testFileValidateIsImage() { |
|
402 $this->assertTrue(file_exists($this->image->uri), 'The image being tested exists.', 'File'); |
|
403 $errors = file_validate_is_image($this->image); |
|
404 $this->assertEqual(count($errors), 0, 'No error reported for our image file.', 'File'); |
|
405 |
|
406 $this->assertTrue(file_exists($this->non_image->uri), 'The non-image being tested exists.', 'File'); |
|
407 $errors = file_validate_is_image($this->non_image); |
|
408 $this->assertEqual(count($errors), 1, 'An error reported for our non-image file.', 'File'); |
|
409 } |
|
410 |
|
411 /** |
|
412 * This ensures the resolution of a specific file is within bounds. |
|
413 * The image will be resized if it's too large. |
|
414 */ |
|
415 function testFileValidateImageResolution() { |
|
416 // Non-images. |
|
417 $errors = file_validate_image_resolution($this->non_image); |
|
418 $this->assertEqual(count($errors), 0, 'Should not get any errors for a non-image file.', 'File'); |
|
419 $errors = file_validate_image_resolution($this->non_image, '50x50', '100x100'); |
|
420 $this->assertEqual(count($errors), 0, 'Do not check the resolution on non files.', 'File'); |
|
421 |
|
422 // Minimum size. |
|
423 $errors = file_validate_image_resolution($this->image); |
|
424 $this->assertEqual(count($errors), 0, 'No errors for an image when there is no minimum or maximum resolution.', 'File'); |
|
425 $errors = file_validate_image_resolution($this->image, 0, '200x1'); |
|
426 $this->assertEqual(count($errors), 1, 'Got an error for an image that was not wide enough.', 'File'); |
|
427 $errors = file_validate_image_resolution($this->image, 0, '1x200'); |
|
428 $this->assertEqual(count($errors), 1, 'Got an error for an image that was not tall enough.', 'File'); |
|
429 $errors = file_validate_image_resolution($this->image, 0, '200x200'); |
|
430 $this->assertEqual(count($errors), 1, 'Small images report an error.', 'File'); |
|
431 |
|
432 // Maximum size. |
|
433 if (image_get_toolkit()) { |
|
434 // Copy the image so that the original doesn't get resized. |
|
435 copy('misc/druplicon.png', 'temporary://druplicon.png'); |
|
436 $this->image->uri = 'temporary://druplicon.png'; |
|
437 |
|
438 $errors = file_validate_image_resolution($this->image, '10x5'); |
|
439 $this->assertEqual(count($errors), 0, 'No errors should be reported when an oversized image can be scaled down.', 'File'); |
|
440 |
|
441 $info = image_get_info($this->image->uri); |
|
442 $this->assertTrue($info['width'] <= 10, 'Image scaled to correct width.', 'File'); |
|
443 $this->assertTrue($info['height'] <= 5, 'Image scaled to correct height.', 'File'); |
|
444 |
|
445 drupal_unlink('temporary://druplicon.png'); |
|
446 } |
|
447 else { |
|
448 // TODO: should check that the error is returned if no toolkit is available. |
|
449 $errors = file_validate_image_resolution($this->image, '5x10'); |
|
450 $this->assertEqual(count($errors), 1, 'Oversize images that cannot be scaled get an error.', 'File'); |
|
451 } |
|
452 } |
|
453 |
|
454 /** |
|
455 * This will ensure the filename length is valid. |
|
456 */ |
|
457 function testFileValidateNameLength() { |
|
458 // Create a new file object. |
|
459 $file = new stdClass(); |
|
460 |
|
461 // Add a filename with an allowed length and test it. |
|
462 $file->filename = str_repeat('x', 240); |
|
463 $this->assertEqual(strlen($file->filename), 240); |
|
464 $errors = file_validate_name_length($file); |
|
465 $this->assertEqual(count($errors), 0, 'No errors reported for 240 length filename.', 'File'); |
|
466 |
|
467 // Add a filename with a length too long and test it. |
|
468 $file->filename = str_repeat('x', 241); |
|
469 $errors = file_validate_name_length($file); |
|
470 $this->assertEqual(count($errors), 1, 'An error reported for 241 length filename.', 'File'); |
|
471 |
|
472 // Add a filename with an empty string and test it. |
|
473 $file->filename = ''; |
|
474 $errors = file_validate_name_length($file); |
|
475 $this->assertEqual(count($errors), 1, 'An error reported for 0 length filename.', 'File'); |
|
476 } |
|
477 |
|
478 |
|
479 /** |
|
480 * Test file_validate_size(). |
|
481 */ |
|
482 function testFileValidateSize() { |
|
483 // Create a file with a size of 1000 bytes, and quotas of only 1 byte. |
|
484 $file = new stdClass(); |
|
485 $file->filesize = 1000; |
|
486 $errors = file_validate_size($file, 0, 0); |
|
487 $this->assertEqual(count($errors), 0, 'No limits means no errors.', 'File'); |
|
488 $errors = file_validate_size($file, 1, 0); |
|
489 $this->assertEqual(count($errors), 1, 'Error for the file being over the limit.', 'File'); |
|
490 $errors = file_validate_size($file, 0, 1); |
|
491 $this->assertEqual(count($errors), 1, 'Error for the user being over their limit.', 'File'); |
|
492 $errors = file_validate_size($file, 1, 1); |
|
493 $this->assertEqual(count($errors), 2, 'Errors for both the file and their limit.', 'File'); |
|
494 } |
|
495 } |
|
496 |
|
497 |
|
498 |
|
499 /** |
|
500 * Tests the file_unmanaged_save_data() function. |
|
501 */ |
|
502 class FileUnmanagedSaveDataTest extends FileTestCase { |
|
503 public static function getInfo() { |
|
504 return array( |
|
505 'name' => 'Unmanaged file save data', |
|
506 'description' => 'Tests the unmanaged file save data function.', |
|
507 'group' => 'File API', |
|
508 ); |
|
509 } |
|
510 |
|
511 /** |
|
512 * Test the file_unmanaged_save_data() function. |
|
513 */ |
|
514 function testFileSaveData() { |
|
515 $contents = $this->randomName(8); |
|
516 |
|
517 // No filename. |
|
518 $filepath = file_unmanaged_save_data($contents); |
|
519 $this->assertTrue($filepath, 'Unnamed file saved correctly.'); |
|
520 $this->assertEqual(file_uri_scheme($filepath), file_default_scheme(), "File was placed in Drupal's files directory."); |
|
521 $this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.'); |
|
522 |
|
523 // Provide a filename. |
|
524 $filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE); |
|
525 $this->assertTrue($filepath, 'Unnamed file saved correctly.'); |
|
526 $this->assertEqual('asdf.txt', drupal_basename($filepath), 'File was named correctly.'); |
|
527 $this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.'); |
|
528 $this->assertFilePermissions($filepath, variable_get('file_chmod_file', 0664)); |
|
529 } |
|
530 } |
|
531 |
|
532 /** |
|
533 * Tests the file_unmanaged_save_data() function on remote filesystems. |
|
534 */ |
|
535 class RemoteFileUnmanagedSaveDataTest extends FileUnmanagedSaveDataTest { |
|
536 public static function getInfo() { |
|
537 $info = parent::getInfo(); |
|
538 $info['group'] = 'File API (remote)'; |
|
539 return $info; |
|
540 } |
|
541 |
|
542 function setUp() { |
|
543 parent::setUp('file_test'); |
|
544 variable_set('file_default_scheme', 'dummy-remote'); |
|
545 } |
|
546 } |
|
547 |
|
548 /** |
|
549 * Test the file_save_upload() function. |
|
550 */ |
|
551 class FileSaveUploadTest extends FileHookTestCase { |
|
552 /** |
|
553 * An image file path for uploading. |
|
554 */ |
|
555 protected $image; |
|
556 |
|
557 /** |
|
558 * A PHP file path for upload security testing. |
|
559 */ |
|
560 protected $phpfile; |
|
561 |
|
562 /** |
|
563 * The largest file id when the test starts. |
|
564 */ |
|
565 protected $maxFidBefore; |
|
566 |
|
567 public static function getInfo() { |
|
568 return array( |
|
569 'name' => 'File uploading', |
|
570 'description' => 'Tests the file uploading functions.', |
|
571 'group' => 'File API', |
|
572 ); |
|
573 } |
|
574 |
|
575 function setUp() { |
|
576 parent::setUp(); |
|
577 $account = $this->drupalCreateUser(array('access content')); |
|
578 $this->drupalLogin($account); |
|
579 |
|
580 $image_files = $this->drupalGetTestFiles('image'); |
|
581 $this->image = current($image_files); |
|
582 |
|
583 list(, $this->image_extension) = explode('.', $this->image->filename); |
|
584 $this->assertTrue(is_file($this->image->uri), "The image file we're going to upload exists."); |
|
585 |
|
586 $this->phpfile = current($this->drupalGetTestFiles('php')); |
|
587 $this->assertTrue(is_file($this->phpfile->uri), "The PHP file we're going to upload exists."); |
|
588 |
|
589 $this->maxFidBefore = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); |
|
590 |
|
591 // Upload with replace to guarantee there's something there. |
|
592 $edit = array( |
|
593 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
594 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
595 ); |
|
596 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
597 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
598 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
599 |
|
600 // Check that the correct hooks were called then clean out the hook |
|
601 // counters. |
|
602 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
603 file_test_reset(); |
|
604 } |
|
605 |
|
606 /** |
|
607 * Test the file_save_upload() function. |
|
608 */ |
|
609 function testNormal() { |
|
610 $max_fid_after = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); |
|
611 $this->assertTrue($max_fid_after > $this->maxFidBefore, 'A new file was created.'); |
|
612 $file1 = file_load($max_fid_after); |
|
613 $this->assertTrue($file1, 'Loaded the file.'); |
|
614 // MIME type of the uploaded image may be either image/jpeg or image/png. |
|
615 $this->assertEqual(substr($file1->filemime, 0, 5), 'image', 'A MIME type was set.'); |
|
616 |
|
617 // Reset the hook counters to get rid of the 'load' we just called. |
|
618 file_test_reset(); |
|
619 |
|
620 // Upload a second file. |
|
621 $max_fid_before = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); |
|
622 $image2 = current($this->drupalGetTestFiles('image')); |
|
623 $edit = array('files[file_test_upload]' => drupal_realpath($image2->uri)); |
|
624 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
625 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
626 $this->assertRaw(t('You WIN!')); |
|
627 $max_fid_after = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); |
|
628 |
|
629 // Check that the correct hooks were called. |
|
630 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
631 |
|
632 $file2 = file_load($max_fid_after); |
|
633 $this->assertTrue($file2); |
|
634 // MIME type of the uploaded image may be either image/jpeg or image/png. |
|
635 $this->assertEqual(substr($file2->filemime, 0, 5), 'image', 'A MIME type was set.'); |
|
636 |
|
637 // Load both files using file_load_multiple(). |
|
638 $files = file_load_multiple(array($file1->fid, $file2->fid)); |
|
639 $this->assertTrue(isset($files[$file1->fid]), 'File was loaded successfully'); |
|
640 $this->assertTrue(isset($files[$file2->fid]), 'File was loaded successfully'); |
|
641 |
|
642 // Upload a third file to a subdirectory. |
|
643 $image3 = current($this->drupalGetTestFiles('image')); |
|
644 $image3_realpath = drupal_realpath($image3->uri); |
|
645 $dir = $this->randomName(); |
|
646 $edit = array( |
|
647 'files[file_test_upload]' => $image3_realpath, |
|
648 'file_subdir' => $dir, |
|
649 ); |
|
650 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
651 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
652 $this->assertRaw(t('You WIN!')); |
|
653 $this->assertTrue(is_file('temporary://' . $dir . '/' . trim(drupal_basename($image3_realpath)))); |
|
654 |
|
655 // Check that file_load_multiple() with no arguments returns FALSE. |
|
656 $this->assertFalse(file_load_multiple(), 'No files were loaded.'); |
|
657 } |
|
658 |
|
659 /** |
|
660 * Test extension handling. |
|
661 */ |
|
662 function testHandleExtension() { |
|
663 // The file being tested is a .gif which is in the default safe list |
|
664 // of extensions to allow when the extension validator isn't used. This is |
|
665 // implicitly tested at the testNormal() test. Here we tell |
|
666 // file_save_upload() to only allow ".foo". |
|
667 $extensions = 'foo'; |
|
668 $edit = array( |
|
669 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
670 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
671 'extensions' => $extensions, |
|
672 ); |
|
673 |
|
674 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
675 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
676 $message = t('Only files with the following extensions are allowed:') . ' <em class="placeholder">' . $extensions . '</em>'; |
|
677 $this->assertRaw($message, 'Cannot upload a disallowed extension'); |
|
678 $this->assertRaw(t('Epic upload FAIL!'), 'Found the failure message.'); |
|
679 |
|
680 // Check that the correct hooks were called. |
|
681 $this->assertFileHooksCalled(array('validate')); |
|
682 |
|
683 // Reset the hook counters. |
|
684 file_test_reset(); |
|
685 |
|
686 $extensions = 'foo ' . $this->image_extension; |
|
687 // Now tell file_save_upload() to allow the extension of our test image. |
|
688 $edit = array( |
|
689 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
690 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
691 'extensions' => $extensions, |
|
692 ); |
|
693 |
|
694 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
695 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
696 $this->assertNoRaw(t('Only files with the following extensions are allowed:'), 'Can upload an allowed extension.'); |
|
697 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
698 |
|
699 // Check that the correct hooks were called. |
|
700 $this->assertFileHooksCalled(array('validate', 'load', 'update')); |
|
701 |
|
702 // Reset the hook counters. |
|
703 file_test_reset(); |
|
704 |
|
705 // Now tell file_save_upload() to allow any extension. |
|
706 $edit = array( |
|
707 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
708 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
709 'allow_all_extensions' => TRUE, |
|
710 ); |
|
711 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
712 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
713 $this->assertNoRaw(t('Only files with the following extensions are allowed:'), 'Can upload any extension.'); |
|
714 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
715 |
|
716 // Check that the correct hooks were called. |
|
717 $this->assertFileHooksCalled(array('validate', 'load', 'update')); |
|
718 } |
|
719 |
|
720 /** |
|
721 * Test dangerous file handling. |
|
722 */ |
|
723 function testHandleDangerousFile() { |
|
724 // Allow the .php extension and make sure it gets renamed to .txt for |
|
725 // safety. Also check to make sure its MIME type was changed. |
|
726 $edit = array( |
|
727 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
728 'files[file_test_upload]' => drupal_realpath($this->phpfile->uri), |
|
729 'is_image_file' => FALSE, |
|
730 'extensions' => 'php', |
|
731 ); |
|
732 |
|
733 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
734 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
735 $message = t('For security reasons, your upload has been renamed to') . ' <em class="placeholder">' . $this->phpfile->filename . '.txt' . '</em>'; |
|
736 $this->assertRaw($message, 'Dangerous file was renamed.'); |
|
737 $this->assertRaw(t('File MIME type is text/plain.'), "Dangerous file's MIME type was changed."); |
|
738 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
739 |
|
740 // Check that the correct hooks were called. |
|
741 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
742 |
|
743 // Ensure dangerous files are not renamed when insecure uploads is TRUE. |
|
744 // Turn on insecure uploads. |
|
745 variable_set('allow_insecure_uploads', 1); |
|
746 // Reset the hook counters. |
|
747 file_test_reset(); |
|
748 |
|
749 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
750 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
751 $this->assertNoRaw(t('For security reasons, your upload has been renamed'), 'Found no security message.'); |
|
752 $this->assertRaw(t('File name is !filename', array('!filename' => $this->phpfile->filename)), 'Dangerous file was not renamed when insecure uploads is TRUE.'); |
|
753 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
754 |
|
755 // Check that the correct hooks were called. |
|
756 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
757 |
|
758 // Turn off insecure uploads. |
|
759 variable_set('allow_insecure_uploads', 0); |
|
760 } |
|
761 |
|
762 /** |
|
763 * Test file munge handling. |
|
764 */ |
|
765 function testHandleFileMunge() { |
|
766 // Ensure insecure uploads are disabled for this test. |
|
767 variable_set('allow_insecure_uploads', 0); |
|
768 $this->image = file_move($this->image, $this->image->uri . '.foo.' . $this->image_extension); |
|
769 |
|
770 // Reset the hook counters to get rid of the 'move' we just called. |
|
771 file_test_reset(); |
|
772 |
|
773 $extensions = $this->image_extension; |
|
774 $edit = array( |
|
775 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
776 'extensions' => $extensions, |
|
777 ); |
|
778 |
|
779 $munged_filename = $this->image->filename; |
|
780 $munged_filename = substr($munged_filename, 0, strrpos($munged_filename, '.')); |
|
781 $munged_filename .= '_.' . $this->image_extension; |
|
782 |
|
783 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
784 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
785 $this->assertRaw(t('For security reasons, your upload has been renamed'), 'Found security message.'); |
|
786 $this->assertRaw(t('File name is !filename', array('!filename' => $munged_filename)), 'File was successfully munged.'); |
|
787 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
788 |
|
789 // Check that the correct hooks were called. |
|
790 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
791 |
|
792 // Ensure we don't munge files if we're allowing any extension. |
|
793 // Reset the hook counters. |
|
794 file_test_reset(); |
|
795 |
|
796 $edit = array( |
|
797 'files[file_test_upload]' => drupal_realpath($this->image->uri), |
|
798 'allow_all_extensions' => TRUE, |
|
799 ); |
|
800 |
|
801 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
802 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
803 $this->assertNoRaw(t('For security reasons, your upload has been renamed'), 'Found no security message.'); |
|
804 $this->assertRaw(t('File name is !filename', array('!filename' => $this->image->filename)), 'File was not munged when allowing any extension.'); |
|
805 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
806 |
|
807 // Check that the correct hooks were called. |
|
808 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
809 } |
|
810 |
|
811 /** |
|
812 * Test renaming when uploading over a file that already exists. |
|
813 */ |
|
814 function testExistingRename() { |
|
815 $edit = array( |
|
816 'file_test_replace' => FILE_EXISTS_RENAME, |
|
817 'files[file_test_upload]' => drupal_realpath($this->image->uri) |
|
818 ); |
|
819 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
820 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
821 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
822 |
|
823 // Check that the correct hooks were called. |
|
824 $this->assertFileHooksCalled(array('validate', 'insert')); |
|
825 } |
|
826 |
|
827 /** |
|
828 * Test replacement when uploading over a file that already exists. |
|
829 */ |
|
830 function testExistingReplace() { |
|
831 $edit = array( |
|
832 'file_test_replace' => FILE_EXISTS_REPLACE, |
|
833 'files[file_test_upload]' => drupal_realpath($this->image->uri) |
|
834 ); |
|
835 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
836 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
837 $this->assertRaw(t('You WIN!'), 'Found the success message.'); |
|
838 |
|
839 // Check that the correct hooks were called. |
|
840 $this->assertFileHooksCalled(array('validate', 'load', 'update')); |
|
841 } |
|
842 |
|
843 /** |
|
844 * Test for failure when uploading over a file that already exists. |
|
845 */ |
|
846 function testExistingError() { |
|
847 $edit = array( |
|
848 'file_test_replace' => FILE_EXISTS_ERROR, |
|
849 'files[file_test_upload]' => drupal_realpath($this->image->uri) |
|
850 ); |
|
851 $this->drupalPost('file-test/upload', $edit, t('Submit')); |
|
852 $this->assertResponse(200, 'Received a 200 response for posted test file.'); |
|
853 $this->assertRaw(t('Epic upload FAIL!'), 'Found the failure message.'); |
|
854 |
|
855 // Check that the no hooks were called while failing. |
|
856 $this->assertFileHooksCalled(array()); |
|
857 } |
|
858 |
|
859 /** |
|
860 * Test for no failures when not uploading a file. |
|
861 */ |
|
862 function testNoUpload() { |
|
863 $this->drupalPost('file-test/upload', array(), t('Submit')); |
|
864 $this->assertNoRaw(t('Epic upload FAIL!'), 'Failure message not found.'); |
|
865 } |
|
866 } |
|
867 |
|
868 /** |
|
869 * Test the file_save_upload() function on remote filesystems. |
|
870 */ |
|
871 class RemoteFileSaveUploadTest extends FileSaveUploadTest { |
|
872 public static function getInfo() { |
|
873 $info = parent::getInfo(); |
|
874 $info['group'] = 'File API (remote)'; |
|
875 return $info; |
|
876 } |
|
877 |
|
878 function setUp() { |
|
879 parent::setUp('file_test'); |
|
880 variable_set('file_default_scheme', 'dummy-remote'); |
|
881 } |
|
882 } |
|
883 |
|
884 /** |
|
885 * Directory related tests. |
|
886 */ |
|
887 class FileDirectoryTest extends FileTestCase { |
|
888 public static function getInfo() { |
|
889 return array( |
|
890 'name' => 'File paths and directories', |
|
891 'description' => 'Tests operations dealing with directories.', |
|
892 'group' => 'File API', |
|
893 ); |
|
894 } |
|
895 |
|
896 /** |
|
897 * Test directory handling functions. |
|
898 */ |
|
899 function testFileCheckDirectoryHandling() { |
|
900 // A directory to operate on. |
|
901 $directory = file_default_scheme() . '://' . $this->randomName() . '/' . $this->randomName(); |
|
902 $this->assertFalse(is_dir($directory), 'Directory does not exist prior to testing.'); |
|
903 |
|
904 // Non-existent directory. |
|
905 $this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for non-existing directory.', 'File'); |
|
906 |
|
907 // Make a directory. |
|
908 $this->assertTrue(file_prepare_directory($directory, FILE_CREATE_DIRECTORY), 'No error reported when creating a new directory.', 'File'); |
|
909 |
|
910 // Make sure directory actually exists. |
|
911 $this->assertTrue(is_dir($directory), 'Directory actually exists.', 'File'); |
|
912 |
|
913 if (substr(PHP_OS, 0, 3) != 'WIN') { |
|
914 // PHP on Windows doesn't support any kind of useful read-only mode for |
|
915 // directories. When executing a chmod() on a directory, PHP only sets the |
|
916 // read-only flag, which doesn't prevent files to actually be written |
|
917 // in the directory on any recent version of Windows. |
|
918 |
|
919 // Make directory read only. |
|
920 @drupal_chmod($directory, 0444); |
|
921 $this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for a non-writeable directory.', 'File'); |
|
922 |
|
923 // Test directory permission modification. |
|
924 $this->assertTrue(file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS), 'No error reported when making directory writeable.', 'File'); |
|
925 } |
|
926 |
|
927 // Test that the directory has the correct permissions. |
|
928 $this->assertDirectoryPermissions($directory, variable_get('file_chmod_directory', 0775)); |
|
929 |
|
930 // Remove .htaccess file to then test that it gets re-created. |
|
931 @drupal_unlink(file_default_scheme() . '://.htaccess'); |
|
932 $this->assertFalse(is_file(file_default_scheme() . '://.htaccess'), 'Successfully removed the .htaccess file in the files directory.', 'File'); |
|
933 file_ensure_htaccess(); |
|
934 $this->assertTrue(is_file(file_default_scheme() . '://.htaccess'), 'Successfully re-created the .htaccess file in the files directory.', 'File'); |
|
935 // Verify contents of .htaccess file. |
|
936 $file = file_get_contents(file_default_scheme() . '://.htaccess'); |
|
937 $this->assertEqual($file, file_htaccess_lines(FALSE), 'The .htaccess file contains the proper content.', 'File'); |
|
938 } |
|
939 |
|
940 /** |
|
941 * This will take a directory and path, and find a valid filepath that is not |
|
942 * taken by another file. |
|
943 */ |
|
944 function testFileCreateNewFilepath() { |
|
945 // First we test against an imaginary file that does not exist in a |
|
946 // directory. |
|
947 $basename = 'xyz.txt'; |
|
948 $directory = 'misc'; |
|
949 $original = $directory . '/' . $basename; |
|
950 $path = file_create_filename($basename, $directory); |
|
951 $this->assertEqual($path, $original, format_string('New filepath %new equals %original.', array('%new' => $path, '%original' => $original)), 'File'); |
|
952 |
|
953 // Then we test against a file that already exists within that directory. |
|
954 $basename = 'druplicon.png'; |
|
955 $original = $directory . '/' . $basename; |
|
956 $expected = $directory . '/druplicon_0.png'; |
|
957 $path = file_create_filename($basename, $directory); |
|
958 $this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new.', array('%new' => $path, '%original' => $original)), 'File'); |
|
959 |
|
960 // @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix. |
|
961 } |
|
962 |
|
963 /** |
|
964 * This will test the filepath for a destination based on passed flags and |
|
965 * whether or not the file exists. |
|
966 * |
|
967 * If a file exists, file_destination($destination, $replace) will either |
|
968 * return: |
|
969 * - the existing filepath, if $replace is FILE_EXISTS_REPLACE |
|
970 * - a new filepath if FILE_EXISTS_RENAME |
|
971 * - an error (returning FALSE) if FILE_EXISTS_ERROR. |
|
972 * If the file doesn't currently exist, then it will simply return the |
|
973 * filepath. |
|
974 */ |
|
975 function testFileDestination() { |
|
976 // First test for non-existent file. |
|
977 $destination = 'misc/xyz.txt'; |
|
978 $path = file_destination($destination, FILE_EXISTS_REPLACE); |
|
979 $this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_REPLACE.', 'File'); |
|
980 $path = file_destination($destination, FILE_EXISTS_RENAME); |
|
981 $this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_RENAME.', 'File'); |
|
982 $path = file_destination($destination, FILE_EXISTS_ERROR); |
|
983 $this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_ERROR.', 'File'); |
|
984 |
|
985 $destination = 'misc/druplicon.png'; |
|
986 $path = file_destination($destination, FILE_EXISTS_REPLACE); |
|
987 $this->assertEqual($path, $destination, 'Existing filepath destination remains the same with FILE_EXISTS_REPLACE.', 'File'); |
|
988 $path = file_destination($destination, FILE_EXISTS_RENAME); |
|
989 $this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME.', 'File'); |
|
990 $path = file_destination($destination, FILE_EXISTS_ERROR); |
|
991 $this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FILE_EXISTS_ERROR.', 'File'); |
|
992 } |
|
993 |
|
994 /** |
|
995 * Ensure that the file_directory_temp() function always returns a value. |
|
996 */ |
|
997 function testFileDirectoryTemp() { |
|
998 // Start with an empty variable to ensure we have a clean slate. |
|
999 variable_set('file_temporary_path', ''); |
|
1000 $tmp_directory = file_directory_temp(); |
|
1001 $this->assertEqual(empty($tmp_directory), FALSE, 'file_directory_temp() returned a non-empty value.'); |
|
1002 $setting = variable_get('file_temporary_path', ''); |
|
1003 $this->assertEqual($setting, $tmp_directory, "The 'file_temporary_path' variable has the same value that file_directory_temp() returned."); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 /** |
|
1008 * Directory related tests. |
|
1009 */ |
|
1010 class RemoteFileDirectoryTest extends FileDirectoryTest { |
|
1011 public static function getInfo() { |
|
1012 $info = parent::getInfo(); |
|
1013 $info['group'] = 'File API (remote)'; |
|
1014 return $info; |
|
1015 } |
|
1016 |
|
1017 function setUp() { |
|
1018 parent::setUp('file_test'); |
|
1019 variable_set('file_default_scheme', 'dummy-remote'); |
|
1020 } |
|
1021 } |
|
1022 |
|
1023 /** |
|
1024 * Tests the file_scan_directory() function. |
|
1025 */ |
|
1026 class FileScanDirectoryTest extends FileTestCase { |
|
1027 public static function getInfo() { |
|
1028 return array( |
|
1029 'name' => 'File scan directory', |
|
1030 'description' => 'Tests the file_scan_directory() function.', |
|
1031 'group' => 'File API', |
|
1032 ); |
|
1033 } |
|
1034 |
|
1035 function setUp() { |
|
1036 parent::setUp(); |
|
1037 $this->path = drupal_get_path('module', 'simpletest') . '/files'; |
|
1038 } |
|
1039 |
|
1040 /** |
|
1041 * Check the format of the returned values. |
|
1042 */ |
|
1043 function testReturn() { |
|
1044 // Grab a listing of all the JavaSscript files and check that they're |
|
1045 // passed to the callback. |
|
1046 $all_files = file_scan_directory($this->path, '/^javascript-/'); |
|
1047 ksort($all_files); |
|
1048 $this->assertEqual(2, count($all_files), 'Found two, expected javascript files.'); |
|
1049 |
|
1050 // Check the first file. |
|
1051 $file = reset($all_files); |
|
1052 $this->assertEqual(key($all_files), $file->uri, 'Correct array key was used for the first returned file.'); |
|
1053 $this->assertEqual($file->uri, $this->path . '/javascript-1.txt', 'First file name was set correctly.'); |
|
1054 $this->assertEqual($file->filename, 'javascript-1.txt', 'First basename was set correctly'); |
|
1055 $this->assertEqual($file->name, 'javascript-1', 'First name was set correctly.'); |
|
1056 |
|
1057 // Check the second file. |
|
1058 $file = next($all_files); |
|
1059 $this->assertEqual(key($all_files), $file->uri, 'Correct array key was used for the second returned file.'); |
|
1060 $this->assertEqual($file->uri, $this->path . '/javascript-2.script', 'Second file name was set correctly.'); |
|
1061 $this->assertEqual($file->filename, 'javascript-2.script', 'Second basename was set correctly'); |
|
1062 $this->assertEqual($file->name, 'javascript-2', 'Second name was set correctly.'); |
|
1063 } |
|
1064 |
|
1065 /** |
|
1066 * Check that the callback function is called correctly. |
|
1067 */ |
|
1068 function testOptionCallback() { |
|
1069 // When nothing is matched nothing should be passed to the callback. |
|
1070 $all_files = file_scan_directory($this->path, '/^NONEXISTINGFILENAME/', array('callback' => 'file_test_file_scan_callback')); |
|
1071 $this->assertEqual(0, count($all_files), 'No files were found.'); |
|
1072 $results = file_test_file_scan_callback(); |
|
1073 file_test_file_scan_callback_reset(); |
|
1074 $this->assertEqual(0, count($results), 'No files were passed to the callback.'); |
|
1075 |
|
1076 // Grab a listing of all the JavaSscript files and check that they're |
|
1077 // passed to the callback. |
|
1078 $all_files = file_scan_directory($this->path, '/^javascript-/', array('callback' => 'file_test_file_scan_callback')); |
|
1079 $this->assertEqual(2, count($all_files), 'Found two, expected javascript files.'); |
|
1080 $results = file_test_file_scan_callback(); |
|
1081 file_test_file_scan_callback_reset(); |
|
1082 $this->assertEqual(2, count($results), 'Files were passed to the callback.'); |
|
1083 } |
|
1084 |
|
1085 /** |
|
1086 * Check that the no-mask parameter is honored. |
|
1087 */ |
|
1088 function testOptionNoMask() { |
|
1089 // Grab a listing of all the JavaSscript files. |
|
1090 $all_files = file_scan_directory($this->path, '/^javascript-/'); |
|
1091 $this->assertEqual(2, count($all_files), 'Found two, expected javascript files.'); |
|
1092 |
|
1093 // Now use the nomast parameter to filter out the .script file. |
|
1094 $filtered_files = file_scan_directory($this->path, '/^javascript-/', array('nomask' => '/.script$/')); |
|
1095 $this->assertEqual(1, count($filtered_files), 'Filtered correctly.'); |
|
1096 } |
|
1097 |
|
1098 /** |
|
1099 * Check that key parameter sets the return value's key. |
|
1100 */ |
|
1101 function testOptionKey() { |
|
1102 // "filename", for the path starting with $dir. |
|
1103 $expected = array($this->path . '/javascript-1.txt', $this->path . '/javascript-2.script'); |
|
1104 $actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'filepath'))); |
|
1105 sort($actual); |
|
1106 $this->assertEqual($expected, $actual, 'Returned the correct values for the filename key.'); |
|
1107 |
|
1108 // "basename", for the basename of the file. |
|
1109 $expected = array('javascript-1.txt', 'javascript-2.script'); |
|
1110 $actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'filename'))); |
|
1111 sort($actual); |
|
1112 $this->assertEqual($expected, $actual, 'Returned the correct values for the basename key.'); |
|
1113 |
|
1114 // "name" for the name of the file without an extension. |
|
1115 $expected = array('javascript-1', 'javascript-2'); |
|
1116 $actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'name'))); |
|
1117 sort($actual); |
|
1118 $this->assertEqual($expected, $actual, 'Returned the correct values for the name key.'); |
|
1119 |
|
1120 // Invalid option that should default back to "filename". |
|
1121 $expected = array($this->path . '/javascript-1.txt', $this->path . '/javascript-2.script'); |
|
1122 $actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'INVALID'))); |
|
1123 sort($actual); |
|
1124 $this->assertEqual($expected, $actual, 'An invalid key defaulted back to the default.'); |
|
1125 } |
|
1126 |
|
1127 /** |
|
1128 * Check that the recurse option decends into subdirectories. |
|
1129 */ |
|
1130 function testOptionRecurse() { |
|
1131 $files = file_scan_directory(drupal_get_path('module', 'simpletest'), '/^javascript-/', array('recurse' => FALSE)); |
|
1132 $this->assertTrue(empty($files), "Without recursion couldn't find javascript files."); |
|
1133 |
|
1134 $files = file_scan_directory(drupal_get_path('module', 'simpletest'), '/^javascript-/', array('recurse' => TRUE)); |
|
1135 $this->assertEqual(2, count($files), 'With recursion we found the expected javascript files.'); |
|
1136 } |
|
1137 |
|
1138 |
|
1139 /** |
|
1140 * Check that the min_depth options lets us ignore files in the starting |
|
1141 * directory. |
|
1142 */ |
|
1143 function testOptionMinDepth() { |
|
1144 $files = file_scan_directory($this->path, '/^javascript-/', array('min_depth' => 0)); |
|
1145 $this->assertEqual(2, count($files), 'No minimum-depth gets files in current directory.'); |
|
1146 |
|
1147 $files = file_scan_directory($this->path, '/^javascript-/', array('min_depth' => 1)); |
|
1148 $this->assertTrue(empty($files), "Minimum-depth of 1 successfully excludes files from current directory."); |
|
1149 } |
|
1150 } |
|
1151 |
|
1152 /** |
|
1153 * Tests the file_scan_directory() function on remote filesystems. |
|
1154 */ |
|
1155 class RemoteFileScanDirectoryTest extends FileScanDirectoryTest { |
|
1156 public static function getInfo() { |
|
1157 $info = parent::getInfo(); |
|
1158 $info['group'] = 'File API (remote)'; |
|
1159 return $info; |
|
1160 } |
|
1161 |
|
1162 function setUp() { |
|
1163 parent::setUp('file_test'); |
|
1164 variable_set('file_default_scheme', 'dummy-remote'); |
|
1165 } |
|
1166 } |
|
1167 |
|
1168 /** |
|
1169 * Deletion related tests. |
|
1170 */ |
|
1171 class FileUnmanagedDeleteTest extends FileTestCase { |
|
1172 public static function getInfo() { |
|
1173 return array( |
|
1174 'name' => 'Unmanaged file delete', |
|
1175 'description' => 'Tests the unmanaged file delete function.', |
|
1176 'group' => 'File API', |
|
1177 ); |
|
1178 } |
|
1179 |
|
1180 /** |
|
1181 * Delete a normal file. |
|
1182 */ |
|
1183 function testNormal() { |
|
1184 // Create a file for testing |
|
1185 $file = $this->createFile(); |
|
1186 |
|
1187 // Delete a regular file |
|
1188 $this->assertTrue(file_unmanaged_delete($file->uri), 'Deleted worked.'); |
|
1189 $this->assertFalse(file_exists($file->uri), 'Test file has actually been deleted.'); |
|
1190 } |
|
1191 |
|
1192 /** |
|
1193 * Try deleting a missing file. |
|
1194 */ |
|
1195 function testMissing() { |
|
1196 // Try to delete a non-existing file |
|
1197 $this->assertTrue(file_unmanaged_delete(file_default_scheme() . '/' . $this->randomName()), 'Returns true when deleting a non-existent file.'); |
|
1198 } |
|
1199 |
|
1200 /** |
|
1201 * Try deleting a directory. |
|
1202 */ |
|
1203 function testDirectory() { |
|
1204 // A directory to operate on. |
|
1205 $directory = $this->createDirectory(); |
|
1206 |
|
1207 // Try to delete a directory |
|
1208 $this->assertFalse(file_unmanaged_delete($directory), 'Could not delete the delete directory.'); |
|
1209 $this->assertTrue(file_exists($directory), 'Directory has not been deleted.'); |
|
1210 } |
|
1211 } |
|
1212 |
|
1213 /** |
|
1214 * Deletion related tests on remote filesystems. |
|
1215 */ |
|
1216 class RemoteFileUnmanagedDeleteTest extends FileUnmanagedDeleteTest { |
|
1217 public static function getInfo() { |
|
1218 $info = parent::getInfo(); |
|
1219 $info['group'] = 'File API (remote)'; |
|
1220 return $info; |
|
1221 } |
|
1222 |
|
1223 function setUp() { |
|
1224 parent::setUp('file_test'); |
|
1225 variable_set('file_default_scheme', 'dummy-remote'); |
|
1226 } |
|
1227 } |
|
1228 |
|
1229 /** |
|
1230 * Deletion related tests. |
|
1231 */ |
|
1232 class FileUnmanagedDeleteRecursiveTest extends FileTestCase { |
|
1233 public static function getInfo() { |
|
1234 return array( |
|
1235 'name' => 'Unmanaged recursive file delete', |
|
1236 'description' => 'Tests the unmanaged file delete recursive function.', |
|
1237 'group' => 'File API', |
|
1238 ); |
|
1239 } |
|
1240 |
|
1241 /** |
|
1242 * Delete a normal file. |
|
1243 */ |
|
1244 function testSingleFile() { |
|
1245 // Create a file for testing |
|
1246 $filepath = file_default_scheme() . '://' . $this->randomName(); |
|
1247 file_put_contents($filepath, ''); |
|
1248 |
|
1249 // Delete the file. |
|
1250 $this->assertTrue(file_unmanaged_delete_recursive($filepath), 'Function reported success.'); |
|
1251 $this->assertFalse(file_exists($filepath), 'Test file has been deleted.'); |
|
1252 } |
|
1253 |
|
1254 /** |
|
1255 * Try deleting an empty directory. |
|
1256 */ |
|
1257 function testEmptyDirectory() { |
|
1258 // A directory to operate on. |
|
1259 $directory = $this->createDirectory(); |
|
1260 |
|
1261 // Delete the directory. |
|
1262 $this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); |
|
1263 $this->assertFalse(file_exists($directory), 'Directory has been deleted.'); |
|
1264 } |
|
1265 |
|
1266 /** |
|
1267 * Try deleting a directory with some files. |
|
1268 */ |
|
1269 function testDirectory() { |
|
1270 // A directory to operate on. |
|
1271 $directory = $this->createDirectory(); |
|
1272 $filepathA = $directory . '/A'; |
|
1273 $filepathB = $directory . '/B'; |
|
1274 file_put_contents($filepathA, ''); |
|
1275 file_put_contents($filepathB, ''); |
|
1276 |
|
1277 // Delete the directory. |
|
1278 $this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); |
|
1279 $this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.'); |
|
1280 $this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.'); |
|
1281 $this->assertFalse(file_exists($directory), 'Directory has been deleted.'); |
|
1282 } |
|
1283 |
|
1284 /** |
|
1285 * Try deleting subdirectories with some files. |
|
1286 */ |
|
1287 function testSubDirectory() { |
|
1288 // A directory to operate on. |
|
1289 $directory = $this->createDirectory(); |
|
1290 $subdirectory = $this->createDirectory($directory . '/sub'); |
|
1291 $filepathA = $directory . '/A'; |
|
1292 $filepathB = $subdirectory . '/B'; |
|
1293 file_put_contents($filepathA, ''); |
|
1294 file_put_contents($filepathB, ''); |
|
1295 |
|
1296 // Delete the directory. |
|
1297 $this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); |
|
1298 $this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.'); |
|
1299 $this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.'); |
|
1300 $this->assertFalse(file_exists($subdirectory), 'Subdirectory has been deleted.'); |
|
1301 $this->assertFalse(file_exists($directory), 'Directory has been deleted.'); |
|
1302 } |
|
1303 } |
|
1304 |
|
1305 /** |
|
1306 * Deletion related tests on remote filesystems. |
|
1307 */ |
|
1308 class RemoteFileUnmanagedDeleteRecursiveTest extends FileUnmanagedDeleteRecursiveTest { |
|
1309 public static function getInfo() { |
|
1310 $info = parent::getInfo(); |
|
1311 $info['group'] = 'File API (remote)'; |
|
1312 return $info; |
|
1313 } |
|
1314 |
|
1315 function setUp() { |
|
1316 parent::setUp('file_test'); |
|
1317 variable_set('file_default_scheme', 'dummy-remote'); |
|
1318 } |
|
1319 } |
|
1320 |
|
1321 /** |
|
1322 * Unmanaged move related tests. |
|
1323 */ |
|
1324 class FileUnmanagedMoveTest extends FileTestCase { |
|
1325 public static function getInfo() { |
|
1326 return array( |
|
1327 'name' => 'Unmanaged file moving', |
|
1328 'description' => 'Tests the unmanaged file move function.', |
|
1329 'group' => 'File API', |
|
1330 ); |
|
1331 } |
|
1332 |
|
1333 /** |
|
1334 * Move a normal file. |
|
1335 */ |
|
1336 function testNormal() { |
|
1337 // Create a file for testing |
|
1338 $file = $this->createFile(); |
|
1339 |
|
1340 // Moving to a new name. |
|
1341 $desired_filepath = 'public://' . $this->randomName(); |
|
1342 $new_filepath = file_unmanaged_move($file->uri, $desired_filepath, FILE_EXISTS_ERROR); |
|
1343 $this->assertTrue($new_filepath, 'Move was successful.'); |
|
1344 $this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.'); |
|
1345 $this->assertTrue(file_exists($new_filepath), 'File exists at the new location.'); |
|
1346 $this->assertFalse(file_exists($file->uri), 'No file remains at the old location.'); |
|
1347 $this->assertFilePermissions($new_filepath, variable_get('file_chmod_file', 0664)); |
|
1348 |
|
1349 // Moving with rename. |
|
1350 $desired_filepath = 'public://' . $this->randomName(); |
|
1351 $this->assertTrue(file_exists($new_filepath), 'File exists before moving.'); |
|
1352 $this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.'); |
|
1353 $newer_filepath = file_unmanaged_move($new_filepath, $desired_filepath, FILE_EXISTS_RENAME); |
|
1354 $this->assertTrue($newer_filepath, 'Move was successful.'); |
|
1355 $this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.'); |
|
1356 $this->assertTrue(file_exists($newer_filepath), 'File exists at the new location.'); |
|
1357 $this->assertFalse(file_exists($new_filepath), 'No file remains at the old location.'); |
|
1358 $this->assertFilePermissions($newer_filepath, variable_get('file_chmod_file', 0664)); |
|
1359 |
|
1360 // TODO: test moving to a directory (rather than full directory/file path) |
|
1361 // TODO: test creating and moving normal files (rather than streams) |
|
1362 } |
|
1363 |
|
1364 /** |
|
1365 * Try to move a missing file. |
|
1366 */ |
|
1367 function testMissing() { |
|
1368 // Move non-existent file. |
|
1369 $new_filepath = file_unmanaged_move($this->randomName(), $this->randomName()); |
|
1370 $this->assertFalse($new_filepath, 'Moving a missing file fails.'); |
|
1371 } |
|
1372 |
|
1373 /** |
|
1374 * Try to move a file onto itself. |
|
1375 */ |
|
1376 function testOverwriteSelf() { |
|
1377 // Create a file for testing. |
|
1378 $file = $this->createFile(); |
|
1379 |
|
1380 // Move the file onto itself without renaming shouldn't make changes. |
|
1381 $new_filepath = file_unmanaged_move($file->uri, $file->uri, FILE_EXISTS_REPLACE); |
|
1382 $this->assertFalse($new_filepath, 'Moving onto itself without renaming fails.'); |
|
1383 $this->assertTrue(file_exists($file->uri), 'File exists after moving onto itself.'); |
|
1384 |
|
1385 // Move the file onto itself with renaming will result in a new filename. |
|
1386 $new_filepath = file_unmanaged_move($file->uri, $file->uri, FILE_EXISTS_RENAME); |
|
1387 $this->assertTrue($new_filepath, 'Moving onto itself with renaming works.'); |
|
1388 $this->assertFalse(file_exists($file->uri), 'Original file has been removed.'); |
|
1389 $this->assertTrue(file_exists($new_filepath), 'File exists after moving onto itself.'); |
|
1390 } |
|
1391 } |
|
1392 |
|
1393 /** |
|
1394 * Unmanaged move related tests on remote filesystems. |
|
1395 */ |
|
1396 class RemoteFileUnmanagedMoveTest extends FileUnmanagedMoveTest { |
|
1397 public static function getInfo() { |
|
1398 $info = parent::getInfo(); |
|
1399 $info['group'] = 'File API (remote)'; |
|
1400 return $info; |
|
1401 } |
|
1402 |
|
1403 function setUp() { |
|
1404 parent::setUp('file_test'); |
|
1405 variable_set('file_default_scheme', 'dummy-remote'); |
|
1406 } |
|
1407 } |
|
1408 |
|
1409 /** |
|
1410 * Unmanaged copy related tests. |
|
1411 */ |
|
1412 class FileUnmanagedCopyTest extends FileTestCase { |
|
1413 public static function getInfo() { |
|
1414 return array( |
|
1415 'name' => 'Unmanaged file copying', |
|
1416 'description' => 'Tests the unmanaged file copy function.', |
|
1417 'group' => 'File API', |
|
1418 ); |
|
1419 } |
|
1420 |
|
1421 /** |
|
1422 * Copy a normal file. |
|
1423 */ |
|
1424 function testNormal() { |
|
1425 // Create a file for testing |
|
1426 $file = $this->createFile(); |
|
1427 |
|
1428 // Copying to a new name. |
|
1429 $desired_filepath = 'public://' . $this->randomName(); |
|
1430 $new_filepath = file_unmanaged_copy($file->uri, $desired_filepath, FILE_EXISTS_ERROR); |
|
1431 $this->assertTrue($new_filepath, 'Copy was successful.'); |
|
1432 $this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.'); |
|
1433 $this->assertTrue(file_exists($file->uri), 'Original file remains.'); |
|
1434 $this->assertTrue(file_exists($new_filepath), 'New file exists.'); |
|
1435 $this->assertFilePermissions($new_filepath, variable_get('file_chmod_file', 0664)); |
|
1436 |
|
1437 // Copying with rename. |
|
1438 $desired_filepath = 'public://' . $this->randomName(); |
|
1439 $this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.'); |
|
1440 $newer_filepath = file_unmanaged_copy($file->uri, $desired_filepath, FILE_EXISTS_RENAME); |
|
1441 $this->assertTrue($newer_filepath, 'Copy was successful.'); |
|
1442 $this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.'); |
|
1443 $this->assertTrue(file_exists($file->uri), 'Original file remains.'); |
|
1444 $this->assertTrue(file_exists($newer_filepath), 'New file exists.'); |
|
1445 $this->assertFilePermissions($newer_filepath, variable_get('file_chmod_file', 0664)); |
|
1446 |
|
1447 // TODO: test copying to a directory (rather than full directory/file path) |
|
1448 // TODO: test copying normal files using normal paths (rather than only streams) |
|
1449 } |
|
1450 |
|
1451 /** |
|
1452 * Copy a non-existent file. |
|
1453 */ |
|
1454 function testNonExistent() { |
|
1455 // Copy non-existent file |
|
1456 $desired_filepath = $this->randomName(); |
|
1457 $this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exists."); |
|
1458 $new_filepath = file_unmanaged_copy($desired_filepath, $this->randomName()); |
|
1459 $this->assertFalse($new_filepath, 'Copying a missing file fails.'); |
|
1460 } |
|
1461 |
|
1462 /** |
|
1463 * Copy a file onto itself. |
|
1464 */ |
|
1465 function testOverwriteSelf() { |
|
1466 // Create a file for testing |
|
1467 $file = $this->createFile(); |
|
1468 |
|
1469 // Copy the file onto itself with renaming works. |
|
1470 $new_filepath = file_unmanaged_copy($file->uri, $file->uri, FILE_EXISTS_RENAME); |
|
1471 $this->assertTrue($new_filepath, 'Copying onto itself with renaming works.'); |
|
1472 $this->assertNotEqual($new_filepath, $file->uri, 'Copied file has a new name.'); |
|
1473 $this->assertTrue(file_exists($file->uri), 'Original file exists after copying onto itself.'); |
|
1474 $this->assertTrue(file_exists($new_filepath), 'Copied file exists after copying onto itself.'); |
|
1475 $this->assertFilePermissions($new_filepath, variable_get('file_chmod_file', 0664)); |
|
1476 |
|
1477 // Copy the file onto itself without renaming fails. |
|
1478 $new_filepath = file_unmanaged_copy($file->uri, $file->uri, FILE_EXISTS_ERROR); |
|
1479 $this->assertFalse($new_filepath, 'Copying onto itself without renaming fails.'); |
|
1480 $this->assertTrue(file_exists($file->uri), 'File exists after copying onto itself.'); |
|
1481 |
|
1482 // Copy the file into same directory without renaming fails. |
|
1483 $new_filepath = file_unmanaged_copy($file->uri, drupal_dirname($file->uri), FILE_EXISTS_ERROR); |
|
1484 $this->assertFalse($new_filepath, 'Copying onto itself fails.'); |
|
1485 $this->assertTrue(file_exists($file->uri), 'File exists after copying onto itself.'); |
|
1486 |
|
1487 // Copy the file into same directory with renaming works. |
|
1488 $new_filepath = file_unmanaged_copy($file->uri, drupal_dirname($file->uri), FILE_EXISTS_RENAME); |
|
1489 $this->assertTrue($new_filepath, 'Copying into same directory works.'); |
|
1490 $this->assertNotEqual($new_filepath, $file->uri, 'Copied file has a new name.'); |
|
1491 $this->assertTrue(file_exists($file->uri), 'Original file exists after copying onto itself.'); |
|
1492 $this->assertTrue(file_exists($new_filepath), 'Copied file exists after copying onto itself.'); |
|
1493 $this->assertFilePermissions($new_filepath, variable_get('file_chmod_file', 0664)); |
|
1494 } |
|
1495 } |
|
1496 |
|
1497 /** |
|
1498 * Unmanaged copy related tests on remote filesystems. |
|
1499 */ |
|
1500 class RemoteFileUnmanagedCopyTest extends FileUnmanagedCopyTest { |
|
1501 public static function getInfo() { |
|
1502 $info = parent::getInfo(); |
|
1503 $info['group'] = 'File API (remote)'; |
|
1504 return $info; |
|
1505 } |
|
1506 |
|
1507 function setUp() { |
|
1508 parent::setUp('file_test'); |
|
1509 variable_set('file_default_scheme', 'dummy-remote'); |
|
1510 } |
|
1511 } |
|
1512 |
|
1513 /** |
|
1514 * Deletion related tests. |
|
1515 */ |
|
1516 class FileDeleteTest extends FileHookTestCase { |
|
1517 public static function getInfo() { |
|
1518 return array( |
|
1519 'name' => 'File delete', |
|
1520 'description' => 'Tests the file delete function.', |
|
1521 'group' => 'File API', |
|
1522 ); |
|
1523 } |
|
1524 |
|
1525 /** |
|
1526 * Tries deleting a normal file (as opposed to a directory, symlink, etc). |
|
1527 */ |
|
1528 function testUnused() { |
|
1529 $file = $this->createFile(); |
|
1530 |
|
1531 // Check that deletion removes the file and database record. |
|
1532 $this->assertTrue(is_file($file->uri), 'File exists.'); |
|
1533 $this->assertIdentical(file_delete($file), TRUE, 'Delete worked.'); |
|
1534 $this->assertFileHooksCalled(array('delete')); |
|
1535 $this->assertFalse(file_exists($file->uri), 'Test file has actually been deleted.'); |
|
1536 $this->assertFalse(file_load($file->fid), 'File was removed from the database.'); |
|
1537 } |
|
1538 |
|
1539 /** |
|
1540 * Tries deleting a file that is in use. |
|
1541 */ |
|
1542 function testInUse() { |
|
1543 $file = $this->createFile(); |
|
1544 file_usage_add($file, 'testing', 'test', 1); |
|
1545 file_usage_add($file, 'testing', 'test', 1); |
|
1546 |
|
1547 file_usage_delete($file, 'testing', 'test', 1); |
|
1548 file_delete($file); |
|
1549 $usage = file_usage_list($file); |
|
1550 $this->assertEqual($usage['testing']['test'], array(1 => 1), 'Test file is still in use.'); |
|
1551 $this->assertTrue(file_exists($file->uri), 'File still exists on the disk.'); |
|
1552 $this->assertTrue(file_load($file->fid), 'File still exists in the database.'); |
|
1553 |
|
1554 // Clear out the call to hook_file_load(). |
|
1555 file_test_reset(); |
|
1556 |
|
1557 file_usage_delete($file, 'testing', 'test', 1); |
|
1558 file_delete($file); |
|
1559 $usage = file_usage_list($file); |
|
1560 $this->assertFileHooksCalled(array('delete')); |
|
1561 $this->assertTrue(empty($usage), 'File usage data was removed.'); |
|
1562 $this->assertFalse(file_exists($file->uri), 'File has been deleted after its last usage was removed.'); |
|
1563 $this->assertFalse(file_load($file->fid), 'File was removed from the database.'); |
|
1564 } |
|
1565 } |
|
1566 |
|
1567 |
|
1568 /** |
|
1569 * Move related tests |
|
1570 */ |
|
1571 class FileMoveTest extends FileHookTestCase { |
|
1572 public static function getInfo() { |
|
1573 return array( |
|
1574 'name' => 'File moving', |
|
1575 'description' => 'Tests the file move function.', |
|
1576 'group' => 'File API', |
|
1577 ); |
|
1578 } |
|
1579 |
|
1580 /** |
|
1581 * Move a normal file. |
|
1582 */ |
|
1583 function testNormal() { |
|
1584 $contents = $this->randomName(10); |
|
1585 $source = $this->createFile(NULL, $contents); |
|
1586 $desired_filepath = 'public://' . $this->randomName(); |
|
1587 |
|
1588 // Clone the object so we don't have to worry about the function changing |
|
1589 // our reference copy. |
|
1590 $result = file_move(clone $source, $desired_filepath, FILE_EXISTS_ERROR); |
|
1591 |
|
1592 // Check the return status and that the contents changed. |
|
1593 $this->assertTrue($result, 'File moved successfully.'); |
|
1594 $this->assertFalse(file_exists($source->uri)); |
|
1595 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file correctly written.'); |
|
1596 |
|
1597 // Check that the correct hooks were called. |
|
1598 $this->assertFileHooksCalled(array('move', 'load', 'update')); |
|
1599 |
|
1600 // Make sure we got the same file back. |
|
1601 $this->assertEqual($source->fid, $result->fid, format_string("Source file id's' %fid is unchanged after move.", array('%fid' => $source->fid))); |
|
1602 |
|
1603 // Reload the file from the database and check that the changes were |
|
1604 // actually saved. |
|
1605 $loaded_file = file_load($result->fid, TRUE); |
|
1606 $this->assertTrue($loaded_file, 'File can be loaded from the database.'); |
|
1607 $this->assertFileUnchanged($result, $loaded_file); |
|
1608 } |
|
1609 |
|
1610 /** |
|
1611 * Test renaming when moving onto a file that already exists. |
|
1612 */ |
|
1613 function testExistingRename() { |
|
1614 // Setup a file to overwrite. |
|
1615 $contents = $this->randomName(10); |
|
1616 $source = $this->createFile(NULL, $contents); |
|
1617 $target = $this->createFile(); |
|
1618 $this->assertDifferentFile($source, $target); |
|
1619 |
|
1620 // Clone the object so we don't have to worry about the function changing |
|
1621 // our reference copy. |
|
1622 $result = file_move(clone $source, $target->uri, FILE_EXISTS_RENAME); |
|
1623 |
|
1624 // Check the return status and that the contents changed. |
|
1625 $this->assertTrue($result, 'File moved successfully.'); |
|
1626 $this->assertFalse(file_exists($source->uri)); |
|
1627 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file correctly written.'); |
|
1628 |
|
1629 // Check that the correct hooks were called. |
|
1630 $this->assertFileHooksCalled(array('move', 'load', 'update')); |
|
1631 |
|
1632 // Compare the returned value to what made it into the database. |
|
1633 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
1634 // The target file should not have been altered. |
|
1635 $this->assertFileUnchanged($target, file_load($target->fid, TRUE)); |
|
1636 // Make sure we end up with two distinct files afterwards. |
|
1637 $this->assertDifferentFile($target, $result); |
|
1638 |
|
1639 // Compare the source and results. |
|
1640 $loaded_source = file_load($source->fid, TRUE); |
|
1641 $this->assertEqual($loaded_source->fid, $result->fid, "Returned file's id matches the source."); |
|
1642 $this->assertNotEqual($loaded_source->uri, $source->uri, 'Returned file path has changed from the original.'); |
|
1643 } |
|
1644 |
|
1645 /** |
|
1646 * Test replacement when moving onto a file that already exists. |
|
1647 */ |
|
1648 function testExistingReplace() { |
|
1649 // Setup a file to overwrite. |
|
1650 $contents = $this->randomName(10); |
|
1651 $source = $this->createFile(NULL, $contents); |
|
1652 $target = $this->createFile(); |
|
1653 $this->assertDifferentFile($source, $target); |
|
1654 |
|
1655 // Clone the object so we don't have to worry about the function changing |
|
1656 // our reference copy. |
|
1657 $result = file_move(clone $source, $target->uri, FILE_EXISTS_REPLACE); |
|
1658 |
|
1659 // Look at the results. |
|
1660 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file were overwritten.'); |
|
1661 $this->assertFalse(file_exists($source->uri)); |
|
1662 $this->assertTrue($result, 'File moved successfully.'); |
|
1663 |
|
1664 // Check that the correct hooks were called. |
|
1665 $this->assertFileHooksCalled(array('move', 'update', 'delete', 'load')); |
|
1666 |
|
1667 // Reload the file from the database and check that the changes were |
|
1668 // actually saved. |
|
1669 $loaded_result = file_load($result->fid, TRUE); |
|
1670 $this->assertFileUnchanged($result, $loaded_result); |
|
1671 // Check that target was re-used. |
|
1672 $this->assertSameFile($target, $loaded_result); |
|
1673 // Source and result should be totally different. |
|
1674 $this->assertDifferentFile($source, $loaded_result); |
|
1675 } |
|
1676 |
|
1677 /** |
|
1678 * Test replacement when moving onto itself. |
|
1679 */ |
|
1680 function testExistingReplaceSelf() { |
|
1681 // Setup a file to overwrite. |
|
1682 $contents = $this->randomName(10); |
|
1683 $source = $this->createFile(NULL, $contents); |
|
1684 |
|
1685 // Copy the file over itself. Clone the object so we don't have to worry |
|
1686 // about the function changing our reference copy. |
|
1687 $result = file_move(clone $source, $source->uri, FILE_EXISTS_REPLACE); |
|
1688 $this->assertFalse($result, 'File move failed.'); |
|
1689 $this->assertEqual($contents, file_get_contents($source->uri), 'Contents of file were not altered.'); |
|
1690 |
|
1691 // Check that no hooks were called while failing. |
|
1692 $this->assertFileHooksCalled(array()); |
|
1693 |
|
1694 // Load the file from the database and make sure it is identical to what |
|
1695 // was returned. |
|
1696 $this->assertFileUnchanged($source, file_load($source->fid, TRUE)); |
|
1697 } |
|
1698 |
|
1699 /** |
|
1700 * Test that moving onto an existing file fails when FILE_EXISTS_ERROR is |
|
1701 * specified. |
|
1702 */ |
|
1703 function testExistingError() { |
|
1704 $contents = $this->randomName(10); |
|
1705 $source = $this->createFile(); |
|
1706 $target = $this->createFile(NULL, $contents); |
|
1707 $this->assertDifferentFile($source, $target); |
|
1708 |
|
1709 // Clone the object so we don't have to worry about the function changing |
|
1710 // our reference copy. |
|
1711 $result = file_move(clone $source, $target->uri, FILE_EXISTS_ERROR); |
|
1712 |
|
1713 // Check the return status and that the contents did not change. |
|
1714 $this->assertFalse($result, 'File move failed.'); |
|
1715 $this->assertTrue(file_exists($source->uri)); |
|
1716 $this->assertEqual($contents, file_get_contents($target->uri), 'Contents of file were not altered.'); |
|
1717 |
|
1718 // Check that no hooks were called while failing. |
|
1719 $this->assertFileHooksCalled(array()); |
|
1720 |
|
1721 // Load the file from the database and make sure it is identical to what |
|
1722 // was returned. |
|
1723 $this->assertFileUnchanged($source, file_load($source->fid, TRUE)); |
|
1724 $this->assertFileUnchanged($target, file_load($target->fid, TRUE)); |
|
1725 } |
|
1726 } |
|
1727 |
|
1728 |
|
1729 /** |
|
1730 * Copy related tests. |
|
1731 */ |
|
1732 class FileCopyTest extends FileHookTestCase { |
|
1733 public static function getInfo() { |
|
1734 return array( |
|
1735 'name' => 'File copying', |
|
1736 'description' => 'Tests the file copy function.', |
|
1737 'group' => 'File API', |
|
1738 ); |
|
1739 } |
|
1740 |
|
1741 /** |
|
1742 * Test file copying in the normal, base case. |
|
1743 */ |
|
1744 function testNormal() { |
|
1745 $contents = $this->randomName(10); |
|
1746 $source = $this->createFile(NULL, $contents); |
|
1747 $desired_uri = 'public://' . $this->randomName(); |
|
1748 |
|
1749 // Clone the object so we don't have to worry about the function changing |
|
1750 // our reference copy. |
|
1751 $result = file_copy(clone $source, $desired_uri, FILE_EXISTS_ERROR); |
|
1752 |
|
1753 // Check the return status and that the contents changed. |
|
1754 $this->assertTrue($result, 'File copied successfully.'); |
|
1755 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file were copied correctly.'); |
|
1756 |
|
1757 // Check that the correct hooks were called. |
|
1758 $this->assertFileHooksCalled(array('copy', 'insert')); |
|
1759 |
|
1760 $this->assertDifferentFile($source, $result); |
|
1761 $this->assertEqual($result->uri, $desired_uri, 'The copied file object has the desired filepath.'); |
|
1762 $this->assertTrue(file_exists($source->uri), 'The original file still exists.'); |
|
1763 $this->assertTrue(file_exists($result->uri), 'The copied file exists.'); |
|
1764 |
|
1765 // Reload the file from the database and check that the changes were |
|
1766 // actually saved. |
|
1767 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
1768 } |
|
1769 |
|
1770 /** |
|
1771 * Test renaming when copying over a file that already exists. |
|
1772 */ |
|
1773 function testExistingRename() { |
|
1774 // Setup a file to overwrite. |
|
1775 $contents = $this->randomName(10); |
|
1776 $source = $this->createFile(NULL, $contents); |
|
1777 $target = $this->createFile(); |
|
1778 $this->assertDifferentFile($source, $target); |
|
1779 |
|
1780 // Clone the object so we don't have to worry about the function changing |
|
1781 // our reference copy. |
|
1782 $result = file_copy(clone $source, $target->uri, FILE_EXISTS_RENAME); |
|
1783 |
|
1784 // Check the return status and that the contents changed. |
|
1785 $this->assertTrue($result, 'File copied successfully.'); |
|
1786 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file were copied correctly.'); |
|
1787 $this->assertNotEqual($result->uri, $source->uri, 'Returned file path has changed from the original.'); |
|
1788 |
|
1789 // Check that the correct hooks were called. |
|
1790 $this->assertFileHooksCalled(array('copy', 'insert')); |
|
1791 |
|
1792 // Load all the affected files to check the changes that actually made it |
|
1793 // to the database. |
|
1794 $loaded_source = file_load($source->fid, TRUE); |
|
1795 $loaded_target = file_load($target->fid, TRUE); |
|
1796 $loaded_result = file_load($result->fid, TRUE); |
|
1797 |
|
1798 // Verify that the source file wasn't changed. |
|
1799 $this->assertFileUnchanged($source, $loaded_source); |
|
1800 |
|
1801 // Verify that what was returned is what's in the database. |
|
1802 $this->assertFileUnchanged($result, $loaded_result); |
|
1803 |
|
1804 // Make sure we end up with three distinct files afterwards. |
|
1805 $this->assertDifferentFile($loaded_source, $loaded_target); |
|
1806 $this->assertDifferentFile($loaded_target, $loaded_result); |
|
1807 $this->assertDifferentFile($loaded_source, $loaded_result); |
|
1808 } |
|
1809 |
|
1810 /** |
|
1811 * Test replacement when copying over a file that already exists. |
|
1812 */ |
|
1813 function testExistingReplace() { |
|
1814 // Setup a file to overwrite. |
|
1815 $contents = $this->randomName(10); |
|
1816 $source = $this->createFile(NULL, $contents); |
|
1817 $target = $this->createFile(); |
|
1818 $this->assertDifferentFile($source, $target); |
|
1819 |
|
1820 // Clone the object so we don't have to worry about the function changing |
|
1821 // our reference copy. |
|
1822 $result = file_copy(clone $source, $target->uri, FILE_EXISTS_REPLACE); |
|
1823 |
|
1824 // Check the return status and that the contents changed. |
|
1825 $this->assertTrue($result, 'File copied successfully.'); |
|
1826 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of file were overwritten.'); |
|
1827 $this->assertDifferentFile($source, $result); |
|
1828 |
|
1829 // Check that the correct hooks were called. |
|
1830 $this->assertFileHooksCalled(array('load', 'copy', 'update')); |
|
1831 |
|
1832 // Load all the affected files to check the changes that actually made it |
|
1833 // to the database. |
|
1834 $loaded_source = file_load($source->fid, TRUE); |
|
1835 $loaded_target = file_load($target->fid, TRUE); |
|
1836 $loaded_result = file_load($result->fid, TRUE); |
|
1837 |
|
1838 // Verify that the source file wasn't changed. |
|
1839 $this->assertFileUnchanged($source, $loaded_source); |
|
1840 |
|
1841 // Verify that what was returned is what's in the database. |
|
1842 $this->assertFileUnchanged($result, $loaded_result); |
|
1843 |
|
1844 // Target file was reused for the result. |
|
1845 $this->assertFileUnchanged($loaded_target, $loaded_result); |
|
1846 } |
|
1847 |
|
1848 /** |
|
1849 * Test that copying over an existing file fails when FILE_EXISTS_ERROR is |
|
1850 * specified. |
|
1851 */ |
|
1852 function testExistingError() { |
|
1853 $contents = $this->randomName(10); |
|
1854 $source = $this->createFile(); |
|
1855 $target = $this->createFile(NULL, $contents); |
|
1856 $this->assertDifferentFile($source, $target); |
|
1857 |
|
1858 // Clone the object so we don't have to worry about the function changing |
|
1859 // our reference copy. |
|
1860 $result = file_copy(clone $source, $target->uri, FILE_EXISTS_ERROR); |
|
1861 |
|
1862 // Check the return status and that the contents were not changed. |
|
1863 $this->assertFalse($result, 'File copy failed.'); |
|
1864 $this->assertEqual($contents, file_get_contents($target->uri), 'Contents of file were not altered.'); |
|
1865 |
|
1866 // Check that the correct hooks were called. |
|
1867 $this->assertFileHooksCalled(array()); |
|
1868 |
|
1869 $this->assertFileUnchanged($source, file_load($source->fid, TRUE)); |
|
1870 $this->assertFileUnchanged($target, file_load($target->fid, TRUE)); |
|
1871 } |
|
1872 } |
|
1873 |
|
1874 |
|
1875 /** |
|
1876 * Tests the file_load() function. |
|
1877 */ |
|
1878 class FileLoadTest extends FileHookTestCase { |
|
1879 public static function getInfo() { |
|
1880 return array( |
|
1881 'name' => 'File loading', |
|
1882 'description' => 'Tests the file_load() function.', |
|
1883 'group' => 'File API', |
|
1884 ); |
|
1885 } |
|
1886 |
|
1887 /** |
|
1888 * Try to load a non-existent file by fid. |
|
1889 */ |
|
1890 function testLoadMissingFid() { |
|
1891 $this->assertFalse(file_load(-1), "Try to load an invalid fid fails."); |
|
1892 $this->assertFileHooksCalled(array()); |
|
1893 } |
|
1894 |
|
1895 /** |
|
1896 * Try to load a non-existent file by URI. |
|
1897 */ |
|
1898 function testLoadMissingFilepath() { |
|
1899 $files = file_load_multiple(array(), array('uri' => 'foobar://misc/druplicon.png')); |
|
1900 $this->assertFalse(reset($files), "Try to load a file that doesn't exist in the database fails."); |
|
1901 $this->assertFileHooksCalled(array()); |
|
1902 } |
|
1903 |
|
1904 /** |
|
1905 * Try to load a non-existent file by status. |
|
1906 */ |
|
1907 function testLoadInvalidStatus() { |
|
1908 $files = file_load_multiple(array(), array('status' => -99)); |
|
1909 $this->assertFalse(reset($files), "Trying to load a file with an invalid status fails."); |
|
1910 $this->assertFileHooksCalled(array()); |
|
1911 } |
|
1912 |
|
1913 /** |
|
1914 * Load a single file and ensure that the correct values are returned. |
|
1915 */ |
|
1916 function testSingleValues() { |
|
1917 // Create a new file object from scratch so we know the values. |
|
1918 $file = $this->createFile('druplicon.txt', NULL, 'public'); |
|
1919 |
|
1920 $by_fid_file = file_load($file->fid); |
|
1921 $this->assertFileHookCalled('load'); |
|
1922 $this->assertTrue(is_object($by_fid_file), 'file_load() returned an object.'); |
|
1923 $this->assertEqual($by_fid_file->fid, $file->fid, 'Loading by fid got the same fid.', 'File'); |
|
1924 $this->assertEqual($by_fid_file->uri, $file->uri, 'Loading by fid got the correct filepath.', 'File'); |
|
1925 $this->assertEqual($by_fid_file->filename, $file->filename, 'Loading by fid got the correct filename.', 'File'); |
|
1926 $this->assertEqual($by_fid_file->filemime, $file->filemime, 'Loading by fid got the correct MIME type.', 'File'); |
|
1927 $this->assertEqual($by_fid_file->status, $file->status, 'Loading by fid got the correct status.', 'File'); |
|
1928 $this->assertTrue($by_fid_file->file_test['loaded'], 'file_test_file_load() was able to modify the file during load.'); |
|
1929 } |
|
1930 |
|
1931 /** |
|
1932 * This will test loading file data from the database. |
|
1933 */ |
|
1934 function testMultiple() { |
|
1935 // Create a new file object. |
|
1936 $file = $this->createFile('druplicon.txt', NULL, 'public'); |
|
1937 |
|
1938 // Load by path. |
|
1939 file_test_reset(); |
|
1940 $by_path_files = file_load_multiple(array(), array('uri' => $file->uri)); |
|
1941 $this->assertFileHookCalled('load'); |
|
1942 $this->assertEqual(1, count($by_path_files), 'file_load_multiple() returned an array of the correct size.'); |
|
1943 $by_path_file = reset($by_path_files); |
|
1944 $this->assertTrue($by_path_file->file_test['loaded'], 'file_test_file_load() was able to modify the file during load.'); |
|
1945 $this->assertEqual($by_path_file->fid, $file->fid, 'Loading by filepath got the correct fid.', 'File'); |
|
1946 |
|
1947 // Load by fid. |
|
1948 file_test_reset(); |
|
1949 $by_fid_files = file_load_multiple(array($file->fid), array()); |
|
1950 $this->assertFileHookCalled('load'); |
|
1951 $this->assertEqual(1, count($by_fid_files), 'file_load_multiple() returned an array of the correct size.'); |
|
1952 $by_fid_file = reset($by_fid_files); |
|
1953 $this->assertTrue($by_fid_file->file_test['loaded'], 'file_test_file_load() was able to modify the file during load.'); |
|
1954 $this->assertEqual($by_fid_file->uri, $file->uri, 'Loading by fid got the correct filepath.', 'File'); |
|
1955 } |
|
1956 } |
|
1957 |
|
1958 /** |
|
1959 * Tests the file_save() function. |
|
1960 */ |
|
1961 class FileSaveTest extends FileHookTestCase { |
|
1962 public static function getInfo() { |
|
1963 return array( |
|
1964 'name' => 'File saving', |
|
1965 'description' => 'Tests the file_save() function.', |
|
1966 'group' => 'File API', |
|
1967 ); |
|
1968 } |
|
1969 |
|
1970 function testFileSave() { |
|
1971 // Create a new file object. |
|
1972 $file = array( |
|
1973 'uid' => 1, |
|
1974 'filename' => 'druplicon.txt', |
|
1975 'uri' => 'public://druplicon.txt', |
|
1976 'filemime' => 'text/plain', |
|
1977 'timestamp' => 1, |
|
1978 'status' => FILE_STATUS_PERMANENT, |
|
1979 ); |
|
1980 $file = (object) $file; |
|
1981 file_put_contents($file->uri, 'hello world'); |
|
1982 |
|
1983 // Save it, inserting a new record. |
|
1984 $saved_file = file_save($file); |
|
1985 |
|
1986 // Check that the correct hooks were called. |
|
1987 $this->assertFileHooksCalled(array('insert')); |
|
1988 |
|
1989 $this->assertNotNull($saved_file, 'Saving the file should give us back a file object.', 'File'); |
|
1990 $this->assertTrue($saved_file->fid > 0, 'A new file ID is set when saving a new file to the database.', 'File'); |
|
1991 $loaded_file = db_query('SELECT * FROM {file_managed} f WHERE f.fid = :fid', array(':fid' => $saved_file->fid))->fetch(PDO::FETCH_OBJ); |
|
1992 $this->assertNotNull($loaded_file, 'Record exists in the database.'); |
|
1993 $this->assertEqual($loaded_file->status, $file->status, 'Status was saved correctly.'); |
|
1994 $this->assertEqual($saved_file->filesize, filesize($file->uri), 'File size was set correctly.', 'File'); |
|
1995 $this->assertTrue($saved_file->timestamp > 1, 'File size was set correctly.', 'File'); |
|
1996 |
|
1997 |
|
1998 // Resave the file, updating the existing record. |
|
1999 file_test_reset(); |
|
2000 $saved_file->status = 7; |
|
2001 $resaved_file = file_save($saved_file); |
|
2002 |
|
2003 // Check that the correct hooks were called. |
|
2004 $this->assertFileHooksCalled(array('load', 'update')); |
|
2005 |
|
2006 $this->assertEqual($resaved_file->fid, $saved_file->fid, 'The file ID of an existing file is not changed when updating the database.', 'File'); |
|
2007 $this->assertTrue($resaved_file->timestamp >= $saved_file->timestamp, "Timestamp didn't go backwards.", 'File'); |
|
2008 $loaded_file = db_query('SELECT * FROM {file_managed} f WHERE f.fid = :fid', array(':fid' => $saved_file->fid))->fetch(PDO::FETCH_OBJ); |
|
2009 $this->assertNotNull($loaded_file, 'Record still exists in the database.', 'File'); |
|
2010 $this->assertEqual($loaded_file->status, $saved_file->status, 'Status was saved correctly.'); |
|
2011 |
|
2012 // Try to insert a second file with the same name apart from case insensitivity |
|
2013 // to ensure the 'uri' index allows for filenames with different cases. |
|
2014 $file = (object) array( |
|
2015 'uid' => 1, |
|
2016 'filename' => 'DRUPLICON.txt', |
|
2017 'uri' => 'public://DRUPLICON.txt', |
|
2018 'filemime' => 'text/plain', |
|
2019 'timestamp' => 1, |
|
2020 'status' => FILE_STATUS_PERMANENT, |
|
2021 ); |
|
2022 file_put_contents($file->uri, 'hello world'); |
|
2023 file_save($file); |
|
2024 } |
|
2025 } |
|
2026 |
|
2027 /** |
|
2028 * Tests file usage functions. |
|
2029 */ |
|
2030 class FileUsageTest extends FileTestCase { |
|
2031 public static function getInfo() { |
|
2032 return array( |
|
2033 'name' => 'File usage', |
|
2034 'description' => 'Tests the file usage functions.', |
|
2035 'group' => 'File', |
|
2036 ); |
|
2037 } |
|
2038 |
|
2039 /** |
|
2040 * Tests file_usage_list(). |
|
2041 */ |
|
2042 function testGetUsage() { |
|
2043 $file = $this->createFile(); |
|
2044 db_insert('file_usage') |
|
2045 ->fields(array( |
|
2046 'fid' => $file->fid, |
|
2047 'module' => 'testing', |
|
2048 'type' => 'foo', |
|
2049 'id' => 1, |
|
2050 'count' => 1 |
|
2051 )) |
|
2052 ->execute(); |
|
2053 db_insert('file_usage') |
|
2054 ->fields(array( |
|
2055 'fid' => $file->fid, |
|
2056 'module' => 'testing', |
|
2057 'type' => 'bar', |
|
2058 'id' => 2, |
|
2059 'count' => 2 |
|
2060 )) |
|
2061 ->execute(); |
|
2062 |
|
2063 $usage = file_usage_list($file); |
|
2064 |
|
2065 $this->assertEqual(count($usage['testing']), 2, 'Returned the correct number of items.'); |
|
2066 $this->assertTrue(isset($usage['testing']['foo'][1]), 'Returned the correct id.'); |
|
2067 $this->assertTrue(isset($usage['testing']['bar'][2]), 'Returned the correct id.'); |
|
2068 $this->assertEqual($usage['testing']['foo'][1], 1, 'Returned the correct count.'); |
|
2069 $this->assertEqual($usage['testing']['bar'][2], 2, 'Returned the correct count.'); |
|
2070 } |
|
2071 |
|
2072 /** |
|
2073 * Tests file_usage_add(). |
|
2074 */ |
|
2075 function testAddUsage() { |
|
2076 $file = $this->createFile(); |
|
2077 file_usage_add($file, 'testing', 'foo', 1); |
|
2078 // Add the file twice to ensure that the count is incremented rather than |
|
2079 // creating additional records. |
|
2080 file_usage_add($file, 'testing', 'bar', 2); |
|
2081 file_usage_add($file, 'testing', 'bar', 2); |
|
2082 |
|
2083 $usage = db_select('file_usage', 'f') |
|
2084 ->fields('f') |
|
2085 ->condition('f.fid', $file->fid) |
|
2086 ->execute() |
|
2087 ->fetchAllAssoc('id'); |
|
2088 $this->assertEqual(count($usage), 2, 'Created two records'); |
|
2089 $this->assertEqual($usage[1]->module, 'testing', 'Correct module'); |
|
2090 $this->assertEqual($usage[2]->module, 'testing', 'Correct module'); |
|
2091 $this->assertEqual($usage[1]->type, 'foo', 'Correct type'); |
|
2092 $this->assertEqual($usage[2]->type, 'bar', 'Correct type'); |
|
2093 $this->assertEqual($usage[1]->count, 1, 'Correct count'); |
|
2094 $this->assertEqual($usage[2]->count, 2, 'Correct count'); |
|
2095 } |
|
2096 |
|
2097 /** |
|
2098 * Tests file_usage_delete(). |
|
2099 */ |
|
2100 function testRemoveUsage() { |
|
2101 $file = $this->createFile(); |
|
2102 db_insert('file_usage') |
|
2103 ->fields(array( |
|
2104 'fid' => $file->fid, |
|
2105 'module' => 'testing', |
|
2106 'type' => 'bar', |
|
2107 'id' => 2, |
|
2108 'count' => 3, |
|
2109 )) |
|
2110 ->execute(); |
|
2111 |
|
2112 // Normal decrement. |
|
2113 file_usage_delete($file, 'testing', 'bar', 2); |
|
2114 $count = db_select('file_usage', 'f') |
|
2115 ->fields('f', array('count')) |
|
2116 ->condition('f.fid', $file->fid) |
|
2117 ->execute() |
|
2118 ->fetchField(); |
|
2119 $this->assertEqual(2, $count, 'The count was decremented correctly.'); |
|
2120 |
|
2121 // Multiple decrement and removal. |
|
2122 file_usage_delete($file, 'testing', 'bar', 2, 2); |
|
2123 $count = db_select('file_usage', 'f') |
|
2124 ->fields('f', array('count')) |
|
2125 ->condition('f.fid', $file->fid) |
|
2126 ->execute() |
|
2127 ->fetchField(); |
|
2128 $this->assertIdentical(FALSE, $count, 'The count was removed entirely when empty.'); |
|
2129 |
|
2130 // Non-existent decrement. |
|
2131 file_usage_delete($file, 'testing', 'bar', 2); |
|
2132 $count = db_select('file_usage', 'f') |
|
2133 ->fields('f', array('count')) |
|
2134 ->condition('f.fid', $file->fid) |
|
2135 ->execute() |
|
2136 ->fetchField(); |
|
2137 $this->assertIdentical(FALSE, $count, 'Decrementing non-exist record complete.'); |
|
2138 } |
|
2139 } |
|
2140 |
|
2141 /** |
|
2142 * Tests the file_validate() function.. |
|
2143 */ |
|
2144 class FileValidateTest extends FileHookTestCase { |
|
2145 public static function getInfo() { |
|
2146 return array( |
|
2147 'name' => 'File validate', |
|
2148 'description' => 'Tests the file_validate() function.', |
|
2149 'group' => 'File API', |
|
2150 ); |
|
2151 } |
|
2152 |
|
2153 /** |
|
2154 * Test that the validators passed into are checked. |
|
2155 */ |
|
2156 function testCallerValidation() { |
|
2157 $file = $this->createFile(); |
|
2158 |
|
2159 // Empty validators. |
|
2160 $this->assertEqual(file_validate($file, array()), array(), 'Validating an empty array works successfully.'); |
|
2161 $this->assertFileHooksCalled(array('validate')); |
|
2162 |
|
2163 // Use the file_test.module's test validator to ensure that passing tests |
|
2164 // return correctly. |
|
2165 file_test_reset(); |
|
2166 file_test_set_return('validate', array()); |
|
2167 $passing = array('file_test_validator' => array(array())); |
|
2168 $this->assertEqual(file_validate($file, $passing), array(), 'Validating passes.'); |
|
2169 $this->assertFileHooksCalled(array('validate')); |
|
2170 |
|
2171 // Now test for failures in validators passed in and by hook_validate. |
|
2172 file_test_reset(); |
|
2173 file_test_set_return('validate', array('Epic fail')); |
|
2174 $failing = array('file_test_validator' => array(array('Failed', 'Badly'))); |
|
2175 $this->assertEqual(file_validate($file, $failing), array('Failed', 'Badly', 'Epic fail'), 'Validating returns errors.'); |
|
2176 $this->assertFileHooksCalled(array('validate')); |
|
2177 } |
|
2178 } |
|
2179 |
|
2180 /** |
|
2181 * Tests the file_save_data() function. |
|
2182 */ |
|
2183 class FileSaveDataTest extends FileHookTestCase { |
|
2184 public static function getInfo() { |
|
2185 return array( |
|
2186 'name' => 'File save data', |
|
2187 'description' => 'Tests the file save data function.', |
|
2188 'group' => 'File API', |
|
2189 ); |
|
2190 } |
|
2191 |
|
2192 /** |
|
2193 * Test the file_save_data() function when no filename is provided. |
|
2194 */ |
|
2195 function testWithoutFilename() { |
|
2196 $contents = $this->randomName(8); |
|
2197 |
|
2198 $result = file_save_data($contents); |
|
2199 $this->assertTrue($result, 'Unnamed file saved correctly.'); |
|
2200 |
|
2201 $this->assertEqual(file_default_scheme(), file_uri_scheme($result->uri), "File was placed in Drupal's files directory."); |
|
2202 $this->assertEqual($result->filename, drupal_basename($result->uri), "Filename was set to the file's basename."); |
|
2203 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of the file are correct.'); |
|
2204 $this->assertEqual($result->filemime, 'application/octet-stream', 'A MIME type was set.'); |
|
2205 $this->assertEqual($result->status, FILE_STATUS_PERMANENT, "The file's status was set to permanent."); |
|
2206 |
|
2207 // Check that the correct hooks were called. |
|
2208 $this->assertFileHooksCalled(array('insert')); |
|
2209 |
|
2210 // Verify that what was returned is what's in the database. |
|
2211 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
2212 } |
|
2213 |
|
2214 /** |
|
2215 * Test the file_save_data() function when a filename is provided. |
|
2216 */ |
|
2217 function testWithFilename() { |
|
2218 $contents = $this->randomName(8); |
|
2219 |
|
2220 // Using filename with non-latin characters. |
|
2221 $filename = 'Текстовый файл.txt'; |
|
2222 |
|
2223 $result = file_save_data($contents, 'public://' . $filename); |
|
2224 $this->assertTrue($result, 'Unnamed file saved correctly.'); |
|
2225 |
|
2226 $this->assertEqual('public', file_uri_scheme($result->uri), "File was placed in Drupal's files directory."); |
|
2227 $this->assertEqual($filename, drupal_basename($result->uri), 'File was named correctly.'); |
|
2228 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of the file are correct.'); |
|
2229 $this->assertEqual($result->filemime, 'text/plain', 'A MIME type was set.'); |
|
2230 $this->assertEqual($result->status, FILE_STATUS_PERMANENT, "The file's status was set to permanent."); |
|
2231 |
|
2232 // Check that the correct hooks were called. |
|
2233 $this->assertFileHooksCalled(array('insert')); |
|
2234 |
|
2235 // Verify that what was returned is what's in the database. |
|
2236 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
2237 } |
|
2238 |
|
2239 /** |
|
2240 * Test file_save_data() when renaming around an existing file. |
|
2241 */ |
|
2242 function testExistingRename() { |
|
2243 // Setup a file to overwrite. |
|
2244 $existing = $this->createFile(); |
|
2245 $contents = $this->randomName(8); |
|
2246 |
|
2247 $result = file_save_data($contents, $existing->uri, FILE_EXISTS_RENAME); |
|
2248 $this->assertTrue($result, 'File saved successfully.'); |
|
2249 |
|
2250 $this->assertEqual('public', file_uri_scheme($result->uri), "File was placed in Drupal's files directory."); |
|
2251 $this->assertEqual($result->filename, $existing->filename, 'Filename was set to the basename of the source, rather than that of the renamed file.'); |
|
2252 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of the file are correct.'); |
|
2253 $this->assertEqual($result->filemime, 'application/octet-stream', 'A MIME type was set.'); |
|
2254 $this->assertEqual($result->status, FILE_STATUS_PERMANENT, "The file's status was set to permanent."); |
|
2255 |
|
2256 // Check that the correct hooks were called. |
|
2257 $this->assertFileHooksCalled(array('insert')); |
|
2258 |
|
2259 // Ensure that the existing file wasn't overwritten. |
|
2260 $this->assertDifferentFile($existing, $result); |
|
2261 $this->assertFileUnchanged($existing, file_load($existing->fid, TRUE)); |
|
2262 |
|
2263 // Verify that was returned is what's in the database. |
|
2264 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
2265 } |
|
2266 |
|
2267 /** |
|
2268 * Test file_save_data() when replacing an existing file. |
|
2269 */ |
|
2270 function testExistingReplace() { |
|
2271 // Setup a file to overwrite. |
|
2272 $existing = $this->createFile(); |
|
2273 $contents = $this->randomName(8); |
|
2274 |
|
2275 $result = file_save_data($contents, $existing->uri, FILE_EXISTS_REPLACE); |
|
2276 $this->assertTrue($result, 'File saved successfully.'); |
|
2277 |
|
2278 $this->assertEqual('public', file_uri_scheme($result->uri), "File was placed in Drupal's files directory."); |
|
2279 $this->assertEqual($result->filename, $existing->filename, 'Filename was set to the basename of the existing file, rather than preserving the original name.'); |
|
2280 $this->assertEqual($contents, file_get_contents($result->uri), 'Contents of the file are correct.'); |
|
2281 $this->assertEqual($result->filemime, 'application/octet-stream', 'A MIME type was set.'); |
|
2282 $this->assertEqual($result->status, FILE_STATUS_PERMANENT, "The file's status was set to permanent."); |
|
2283 |
|
2284 // Check that the correct hooks were called. |
|
2285 $this->assertFileHooksCalled(array('load', 'update')); |
|
2286 |
|
2287 // Verify that the existing file was re-used. |
|
2288 $this->assertSameFile($existing, $result); |
|
2289 |
|
2290 // Verify that what was returned is what's in the database. |
|
2291 $this->assertFileUnchanged($result, file_load($result->fid, TRUE)); |
|
2292 } |
|
2293 |
|
2294 /** |
|
2295 * Test that file_save_data() fails overwriting an existing file. |
|
2296 */ |
|
2297 function testExistingError() { |
|
2298 $contents = $this->randomName(8); |
|
2299 $existing = $this->createFile(NULL, $contents); |
|
2300 |
|
2301 // Check the overwrite error. |
|
2302 $result = file_save_data('asdf', $existing->uri, FILE_EXISTS_ERROR); |
|
2303 $this->assertFalse($result, 'Overwriting a file fails when FILE_EXISTS_ERROR is specified.'); |
|
2304 $this->assertEqual($contents, file_get_contents($existing->uri), 'Contents of existing file were unchanged.'); |
|
2305 |
|
2306 // Check that no hooks were called while failing. |
|
2307 $this->assertFileHooksCalled(array()); |
|
2308 |
|
2309 // Ensure that the existing file wasn't overwritten. |
|
2310 $this->assertFileUnchanged($existing, file_load($existing->fid, TRUE)); |
|
2311 } |
|
2312 } |
|
2313 |
|
2314 /** |
|
2315 * Tests for download/file transfer functions. |
|
2316 */ |
|
2317 class FileDownloadTest extends FileTestCase { |
|
2318 public static function getInfo() { |
|
2319 return array( |
|
2320 'name' => 'File download', |
|
2321 'description' => 'Tests for file download/transfer functions.', |
|
2322 'group' => 'File API', |
|
2323 ); |
|
2324 } |
|
2325 |
|
2326 function setUp() { |
|
2327 parent::setUp('file_test'); |
|
2328 // Clear out any hook calls. |
|
2329 file_test_reset(); |
|
2330 } |
|
2331 |
|
2332 /** |
|
2333 * Test the public file transfer system. |
|
2334 */ |
|
2335 function testPublicFileTransfer() { |
|
2336 // Test generating an URL to a created file. |
|
2337 $file = $this->createFile(); |
|
2338 $url = file_create_url($file->uri); |
|
2339 // URLs can't contain characters outside the ASCII set so $filename has to be |
|
2340 // encoded. |
|
2341 $filename = $GLOBALS['base_url'] . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . rawurlencode($file->filename); |
|
2342 $this->assertEqual($filename, $url, 'Correctly generated a URL for a created file.'); |
|
2343 $this->drupalHead($url); |
|
2344 $this->assertResponse(200, 'Confirmed that the generated URL is correct by downloading the created file.'); |
|
2345 |
|
2346 // Test generating an URL to a shipped file (i.e. a file that is part of |
|
2347 // Drupal core, a module or a theme, for example a JavaScript file). |
|
2348 $filepath = 'misc/jquery.js'; |
|
2349 $url = file_create_url($filepath); |
|
2350 $this->assertEqual($GLOBALS['base_url'] . '/' . $filepath, $url, 'Correctly generated a URL for a shipped file.'); |
|
2351 $this->drupalHead($url); |
|
2352 $this->assertResponse(200, 'Confirmed that the generated URL is correct by downloading the shipped file.'); |
|
2353 } |
|
2354 |
|
2355 /** |
|
2356 * Test the private file transfer system. |
|
2357 */ |
|
2358 function testPrivateFileTransfer() { |
|
2359 // Set file downloads to private so handler functions get called. |
|
2360 |
|
2361 // Create a file. |
|
2362 $contents = $this->randomName(8); |
|
2363 $file = $this->createFile(NULL, $contents, 'private'); |
|
2364 $url = file_create_url($file->uri); |
|
2365 |
|
2366 // Set file_test access header to allow the download. |
|
2367 file_test_set_return('download', array('x-foo' => 'Bar')); |
|
2368 $this->drupalGet($url); |
|
2369 $headers = $this->drupalGetHeaders(); |
|
2370 $this->assertEqual($headers['x-foo'], 'Bar', 'Found header set by file_test module on private download.'); |
|
2371 $this->assertResponse(200, 'Correctly allowed access to a file when file_test provides headers.'); |
|
2372 |
|
2373 // Test that the file transferred correctly. |
|
2374 $this->assertEqual($contents, $this->content, 'Contents of the file are correct.'); |
|
2375 |
|
2376 // Deny access to all downloads via a -1 header. |
|
2377 file_test_set_return('download', -1); |
|
2378 $this->drupalHead($url); |
|
2379 $this->assertResponse(403, 'Correctly denied access to a file when file_test sets the header to -1.'); |
|
2380 |
|
2381 // Try non-existent file. |
|
2382 $url = file_create_url('private://' . $this->randomName()); |
|
2383 $this->drupalHead($url); |
|
2384 $this->assertResponse(404, 'Correctly returned 404 response for a non-existent file.'); |
|
2385 } |
|
2386 |
|
2387 /** |
|
2388 * Test file_create_url(). |
|
2389 */ |
|
2390 function testFileCreateUrl() { |
|
2391 global $base_url; |
|
2392 |
|
2393 // Tilde (~) is excluded from this test because it is encoded by |
|
2394 // rawurlencode() in PHP 5.2 but not in PHP 5.3, as per RFC 3986. |
|
2395 // @see http://www.php.net/manual/en/function.rawurlencode.php#86506 |
|
2396 $basename = " -._!$'\"()*@[]?&+%#,;=:\n\x00" . // "Special" ASCII characters. |
|
2397 "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. |
|
2398 "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. |
|
2399 $basename_encoded = '%20-._%21%24%27%22%28%29%2A%40%5B%5D%3F%26%2B%25%23%2C%3B%3D%3A__' . |
|
2400 '%2523%2525%2526%252B%252F%253F' . |
|
2401 '%C3%A9%C3%B8%C3%AF%D0%B2%CE%B2%E4%B8%AD%E5%9C%8B%E6%9B%B8%DB%9E'; |
|
2402 |
|
2403 $this->checkUrl('public', '', $basename, $base_url . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . $basename_encoded); |
|
2404 $this->checkUrl('private', '', $basename, $base_url . '/system/files/' . $basename_encoded); |
|
2405 $this->checkUrl('private', '', $basename, $base_url . '/?q=system/files/' . $basename_encoded, '0'); |
|
2406 } |
|
2407 |
|
2408 /** |
|
2409 * Download a file from the URL generated by file_create_url(). |
|
2410 * |
|
2411 * Create a file with the specified scheme, directory and filename; check that |
|
2412 * the URL generated by file_create_url() for the specified file equals the |
|
2413 * specified URL; fetch the URL and then compare the contents to the file. |
|
2414 * |
|
2415 * @param $scheme |
|
2416 * A scheme, e.g. "public" |
|
2417 * @param $directory |
|
2418 * A directory, possibly "" |
|
2419 * @param $filename |
|
2420 * A filename |
|
2421 * @param $expected_url |
|
2422 * The expected URL |
|
2423 * @param $clean_url |
|
2424 * The value of the clean_url setting |
|
2425 */ |
|
2426 private function checkUrl($scheme, $directory, $filename, $expected_url, $clean_url = '1') { |
|
2427 variable_set('clean_url', $clean_url); |
|
2428 |
|
2429 // Convert $filename to a valid filename, i.e. strip characters not |
|
2430 // supported by the filesystem, and create the file in the specified |
|
2431 // directory. |
|
2432 $filepath = file_create_filename($filename, $directory); |
|
2433 $directory_uri = $scheme . '://' . dirname($filepath); |
|
2434 file_prepare_directory($directory_uri, FILE_CREATE_DIRECTORY); |
|
2435 $file = $this->createFile($filepath, NULL, $scheme); |
|
2436 |
|
2437 $url = file_create_url($file->uri); |
|
2438 $this->assertEqual($url, $expected_url, 'Generated URL matches expected URL.'); |
|
2439 |
|
2440 if ($scheme == 'private') { |
|
2441 // Tell the implementation of hook_file_download() in file_test.module |
|
2442 // that this file may be downloaded. |
|
2443 file_test_set_return('download', array('x-foo' => 'Bar')); |
|
2444 } |
|
2445 |
|
2446 $this->drupalGet($url); |
|
2447 if ($this->assertResponse(200) == 'pass') { |
|
2448 $this->assertRaw(file_get_contents($file->uri), 'Contents of the file are correct.'); |
|
2449 } |
|
2450 |
|
2451 file_delete($file); |
|
2452 } |
|
2453 } |
|
2454 |
|
2455 /** |
|
2456 * Tests for file URL rewriting. |
|
2457 */ |
|
2458 class FileURLRewritingTest extends FileTestCase { |
|
2459 public static function getInfo() { |
|
2460 return array( |
|
2461 'name' => 'File URL rewriting', |
|
2462 'description' => 'Tests for file URL rewriting.', |
|
2463 'group' => 'File', |
|
2464 ); |
|
2465 } |
|
2466 |
|
2467 function setUp() { |
|
2468 parent::setUp('file_test'); |
|
2469 } |
|
2470 |
|
2471 /** |
|
2472 * Test the generating of rewritten shipped file URLs. |
|
2473 */ |
|
2474 function testShippedFileURL() { |
|
2475 // Test generating an URL to a shipped file (i.e. a file that is part of |
|
2476 // Drupal core, a module or a theme, for example a JavaScript file). |
|
2477 |
|
2478 // Test alteration of file URLs to use a CDN. |
|
2479 variable_set('file_test_hook_file_url_alter', 'cdn'); |
|
2480 $filepath = 'misc/jquery.js'; |
|
2481 $url = file_create_url($filepath); |
|
2482 $this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $filepath, $url, 'Correctly generated a CDN URL for a shipped file.'); |
|
2483 $filepath = 'misc/favicon.ico'; |
|
2484 $url = file_create_url($filepath); |
|
2485 $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $filepath, $url, 'Correctly generated a CDN URL for a shipped file.'); |
|
2486 |
|
2487 // Test alteration of file URLs to use root-relative URLs. |
|
2488 variable_set('file_test_hook_file_url_alter', 'root-relative'); |
|
2489 $filepath = 'misc/jquery.js'; |
|
2490 $url = file_create_url($filepath); |
|
2491 $this->assertEqual(base_path() . '/' . $filepath, $url, 'Correctly generated a root-relative URL for a shipped file.'); |
|
2492 $filepath = 'misc/favicon.ico'; |
|
2493 $url = file_create_url($filepath); |
|
2494 $this->assertEqual(base_path() . '/' . $filepath, $url, 'Correctly generated a root-relative URL for a shipped file.'); |
|
2495 |
|
2496 // Test alteration of file URLs to use protocol-relative URLs. |
|
2497 variable_set('file_test_hook_file_url_alter', 'protocol-relative'); |
|
2498 $filepath = 'misc/jquery.js'; |
|
2499 $url = file_create_url($filepath); |
|
2500 $this->assertEqual('/' . base_path() . '/' . $filepath, $url, 'Correctly generated a protocol-relative URL for a shipped file.'); |
|
2501 $filepath = 'misc/favicon.ico'; |
|
2502 $url = file_create_url($filepath); |
|
2503 $this->assertEqual('/' . base_path() . '/' . $filepath, $url, 'Correctly generated a protocol-relative URL for a shipped file.'); |
|
2504 } |
|
2505 |
|
2506 /** |
|
2507 * Test the generating of rewritten public created file URLs. |
|
2508 */ |
|
2509 function testPublicCreatedFileURL() { |
|
2510 // Test generating an URL to a created file. |
|
2511 |
|
2512 // Test alteration of file URLs to use a CDN. |
|
2513 variable_set('file_test_hook_file_url_alter', 'cdn'); |
|
2514 $file = $this->createFile(); |
|
2515 $url = file_create_url($file->uri); |
|
2516 $public_directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); |
|
2517 $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $public_directory_path . '/' . $file->filename, $url, 'Correctly generated a CDN URL for a created file.'); |
|
2518 |
|
2519 // Test alteration of file URLs to use root-relative URLs. |
|
2520 variable_set('file_test_hook_file_url_alter', 'root-relative'); |
|
2521 $file = $this->createFile(); |
|
2522 $url = file_create_url($file->uri); |
|
2523 $this->assertEqual(base_path() . '/' . $public_directory_path . '/' . $file->filename, $url, 'Correctly generated a root-relative URL for a created file.'); |
|
2524 |
|
2525 // Test alteration of file URLs to use a protocol-relative URLs. |
|
2526 variable_set('file_test_hook_file_url_alter', 'protocol-relative'); |
|
2527 $file = $this->createFile(); |
|
2528 $url = file_create_url($file->uri); |
|
2529 $this->assertEqual('/' . base_path() . '/' . $public_directory_path . '/' . $file->filename, $url, 'Correctly generated a protocol-relative URL for a created file.'); |
|
2530 } |
|
2531 } |
|
2532 |
|
2533 /** |
|
2534 * Tests for file_munge_filename() and file_unmunge_filename(). |
|
2535 */ |
|
2536 class FileNameMungingTest extends FileTestCase { |
|
2537 public static function getInfo() { |
|
2538 return array( |
|
2539 'name' => 'File naming', |
|
2540 'description' => 'Test filename munging and unmunging.', |
|
2541 'group' => 'File API', |
|
2542 ); |
|
2543 } |
|
2544 |
|
2545 function setUp() { |
|
2546 parent::setUp(); |
|
2547 $this->bad_extension = 'php'; |
|
2548 $this->name = $this->randomName() . '.' . $this->bad_extension . '.txt'; |
|
2549 $this->name_with_uc_ext = $this->randomName() . '.' . strtoupper($this->bad_extension) . '.txt'; |
|
2550 } |
|
2551 |
|
2552 /** |
|
2553 * Create a file and munge/unmunge the name. |
|
2554 */ |
|
2555 function testMunging() { |
|
2556 // Disable insecure uploads. |
|
2557 variable_set('allow_insecure_uploads', 0); |
|
2558 $munged_name = file_munge_filename($this->name, '', TRUE); |
|
2559 $messages = drupal_get_messages(); |
|
2560 $this->assertTrue(in_array(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $munged_name)), $messages['status']), 'Alert properly set when a file is renamed.'); |
|
2561 $this->assertNotEqual($munged_name, $this->name, format_string('The new filename (%munged) has been modified from the original (%original)', array('%munged' => $munged_name, '%original' => $this->name))); |
|
2562 } |
|
2563 |
|
2564 /** |
|
2565 * Tests munging with a null byte in the filename. |
|
2566 */ |
|
2567 function testMungeNullByte() { |
|
2568 $prefix = $this->randomName(); |
|
2569 $filename = $prefix . '.' . $this->bad_extension . "\0.txt"; |
|
2570 $this->assertEqual(file_munge_filename($filename, ''), $prefix . '.' . $this->bad_extension . '_.txt', 'A filename with a null byte is correctly munged to remove the null byte.'); |
|
2571 } |
|
2572 |
|
2573 /** |
|
2574 * If the allow_insecure_uploads variable evaluates to true, the file should |
|
2575 * come out untouched, no matter how evil the filename. |
|
2576 */ |
|
2577 function testMungeIgnoreInsecure() { |
|
2578 variable_set('allow_insecure_uploads', 1); |
|
2579 $munged_name = file_munge_filename($this->name, ''); |
|
2580 $this->assertIdentical($munged_name, $this->name, format_string('The original filename (%original) matches the munged filename (%munged) when insecure uploads are enabled.', array('%munged' => $munged_name, '%original' => $this->name))); |
|
2581 } |
|
2582 |
|
2583 /** |
|
2584 * White listed extensions are ignored by file_munge_filename(). |
|
2585 */ |
|
2586 function testMungeIgnoreWhitelisted() { |
|
2587 // Declare our extension as whitelisted. The declared extensions should |
|
2588 // be case insensitive so test using one with a different case. |
|
2589 $munged_name = file_munge_filename($this->name_with_uc_ext, $this->bad_extension); |
|
2590 $this->assertIdentical($munged_name, $this->name_with_uc_ext, format_string('The new filename (%munged) matches the original (%original) once the extension has been whitelisted.', array('%munged' => $munged_name, '%original' => $this->name_with_uc_ext))); |
|
2591 // The allowed extensions should also be normalized. |
|
2592 $munged_name = file_munge_filename($this->name, strtoupper($this->bad_extension)); |
|
2593 $this->assertIdentical($munged_name, $this->name, format_string('The new filename (%munged) matches the original (%original) also when the whitelisted extension is in uppercase.', array('%munged' => $munged_name, '%original' => $this->name))); |
|
2594 } |
|
2595 |
|
2596 /** |
|
2597 * Ensure that unmunge gets your name back. |
|
2598 */ |
|
2599 function testUnMunge() { |
|
2600 $munged_name = file_munge_filename($this->name, '', FALSE); |
|
2601 $unmunged_name = file_unmunge_filename($munged_name); |
|
2602 $this->assertIdentical($unmunged_name, $this->name, format_string('The unmunged (%unmunged) filename matches the original (%original)', array('%unmunged' => $unmunged_name, '%original' => $this->name))); |
|
2603 } |
|
2604 } |
|
2605 |
|
2606 /** |
|
2607 * Tests for file_get_mimetype(). |
|
2608 */ |
|
2609 class FileMimeTypeTest extends DrupalWebTestCase { |
|
2610 function setUp() { |
|
2611 parent::setUp('file_test'); |
|
2612 } |
|
2613 |
|
2614 public static function getInfo() { |
|
2615 return array( |
|
2616 'name' => 'File mimetypes', |
|
2617 'description' => 'Test filename mimetype detection.', |
|
2618 'group' => 'File API', |
|
2619 ); |
|
2620 } |
|
2621 |
|
2622 /** |
|
2623 * Test mapping of mimetypes from filenames. |
|
2624 */ |
|
2625 public function testFileMimeTypeDetection() { |
|
2626 $prefix = 'public://'; |
|
2627 |
|
2628 $test_case = array( |
|
2629 'test.jar' => 'application/java-archive', |
|
2630 'test.jpeg' => 'image/jpeg', |
|
2631 'test.JPEG' => 'image/jpeg', |
|
2632 'test.jpg' => 'image/jpeg', |
|
2633 'test.jar.jpg' => 'image/jpeg', |
|
2634 'test.jpg.jar' => 'application/java-archive', |
|
2635 'test.pcf.Z' => 'application/x-font', |
|
2636 'pcf.z' => 'application/octet-stream', |
|
2637 'jar' => 'application/octet-stream', |
|
2638 'some.junk' => 'application/octet-stream', |
|
2639 'foo.file_test_1' => 'madeup/file_test_1', |
|
2640 'foo.file_test_2' => 'madeup/file_test_2', |
|
2641 'foo.doc' => 'madeup/doc', |
|
2642 'test.ogg' => 'audio/ogg', |
|
2643 ); |
|
2644 |
|
2645 // Test using default mappings. |
|
2646 foreach ($test_case as $input => $expected) { |
|
2647 // Test stream [URI]. |
|
2648 $output = file_get_mimetype($prefix . $input); |
|
2649 $this->assertIdentical($output, $expected, format_string('Mimetype for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected))); |
|
2650 |
|
2651 // Test normal path equivalent |
|
2652 $output = file_get_mimetype($input); |
|
2653 $this->assertIdentical($output, $expected, format_string('Mimetype (using default mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected))); |
|
2654 } |
|
2655 |
|
2656 // Now test passing in the map. |
|
2657 $mapping = array( |
|
2658 'mimetypes' => array( |
|
2659 0 => 'application/java-archive', |
|
2660 1 => 'image/jpeg', |
|
2661 ), |
|
2662 'extensions' => array( |
|
2663 'jar' => 0, |
|
2664 'jpg' => 1, |
|
2665 ) |
|
2666 ); |
|
2667 |
|
2668 $test_case = array( |
|
2669 'test.jar' => 'application/java-archive', |
|
2670 'test.jpeg' => 'application/octet-stream', |
|
2671 'test.jpg' => 'image/jpeg', |
|
2672 'test.jar.jpg' => 'image/jpeg', |
|
2673 'test.jpg.jar' => 'application/java-archive', |
|
2674 'test.pcf.z' => 'application/octet-stream', |
|
2675 'pcf.z' => 'application/octet-stream', |
|
2676 'jar' => 'application/octet-stream', |
|
2677 'some.junk' => 'application/octet-stream', |
|
2678 'foo.file_test_1' => 'application/octet-stream', |
|
2679 'foo.file_test_2' => 'application/octet-stream', |
|
2680 'foo.doc' => 'application/octet-stream', |
|
2681 'test.ogg' => 'application/octet-stream', |
|
2682 ); |
|
2683 |
|
2684 foreach ($test_case as $input => $expected) { |
|
2685 $output = file_get_mimetype($input, $mapping); |
|
2686 $this->assertIdentical($output, $expected, format_string('Mimetype (using passed-in mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected))); |
|
2687 } |
|
2688 } |
|
2689 } |
|
2690 |
|
2691 /** |
|
2692 * Tests stream wrapper functions. |
|
2693 */ |
|
2694 class StreamWrapperTest extends DrupalWebTestCase { |
|
2695 |
|
2696 protected $scheme = 'dummy'; |
|
2697 protected $classname = 'DrupalDummyStreamWrapper'; |
|
2698 |
|
2699 public static function getInfo() { |
|
2700 return array( |
|
2701 'name' => 'Stream wrappers', |
|
2702 'description' => 'Tests stream wrapper functions.', |
|
2703 'group' => 'File API', |
|
2704 ); |
|
2705 } |
|
2706 |
|
2707 function setUp() { |
|
2708 parent::setUp('file_test'); |
|
2709 drupal_static_reset('file_get_stream_wrappers'); |
|
2710 } |
|
2711 |
|
2712 function tearDown() { |
|
2713 parent::tearDown(); |
|
2714 stream_wrapper_unregister($this->scheme); |
|
2715 } |
|
2716 |
|
2717 /** |
|
2718 * Test the getClassName() function. |
|
2719 */ |
|
2720 function testGetClassName() { |
|
2721 // Check the dummy scheme. |
|
2722 $this->assertEqual($this->classname, file_stream_wrapper_get_class($this->scheme), 'Got correct class name for dummy scheme.'); |
|
2723 // Check core's scheme. |
|
2724 $this->assertEqual('DrupalPublicStreamWrapper', file_stream_wrapper_get_class('public'), 'Got correct class name for public scheme.'); |
|
2725 } |
|
2726 |
|
2727 /** |
|
2728 * Test the file_stream_wrapper_get_instance_by_scheme() function. |
|
2729 */ |
|
2730 function testGetInstanceByScheme() { |
|
2731 $instance = file_stream_wrapper_get_instance_by_scheme($this->scheme); |
|
2732 $this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy scheme.'); |
|
2733 |
|
2734 $instance = file_stream_wrapper_get_instance_by_scheme('public'); |
|
2735 $this->assertEqual('DrupalPublicStreamWrapper', get_class($instance), 'Got correct class type for public scheme.'); |
|
2736 } |
|
2737 |
|
2738 /** |
|
2739 * Test the URI and target functions. |
|
2740 */ |
|
2741 function testUriFunctions() { |
|
2742 $instance = file_stream_wrapper_get_instance_by_uri($this->scheme . '://foo'); |
|
2743 $this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy URI.'); |
|
2744 |
|
2745 $instance = file_stream_wrapper_get_instance_by_uri('public://foo'); |
|
2746 $this->assertEqual('DrupalPublicStreamWrapper', get_class($instance), 'Got correct class type for public URI.'); |
|
2747 |
|
2748 // Test file_uri_target(). |
|
2749 $this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', 'Got a valid stream target from public://foo/bar.txt.'); |
|
2750 $this->assertFalse(file_uri_target('foo/bar.txt'), 'foo/bar.txt is not a valid stream.'); |
|
2751 |
|
2752 // Test file_build_uri() and DrupalLocalStreamWrapper::getDirectoryPath(). |
|
2753 $this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', 'Expected scheme was added.'); |
|
2754 $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(), variable_get('file_public_path'), 'Expected default directory path was returned.'); |
|
2755 $this->assertEqual(file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(), variable_get('file_temporary_path'), 'Expected temporary directory path was returned.'); |
|
2756 |
|
2757 variable_set('file_default_scheme', 'private'); |
|
2758 $this->assertEqual(file_build_uri('foo/bar.txt'), 'private://foo/bar.txt', 'Got a valid URI from foo/bar.txt.'); |
|
2759 } |
|
2760 |
|
2761 /** |
|
2762 * Test the scheme functions. |
|
2763 */ |
|
2764 function testGetValidStreamScheme() { |
|
2765 $this->assertEqual('foo', file_uri_scheme('foo://pork//chops'), 'Got the correct scheme from foo://asdf'); |
|
2766 $this->assertTrue(file_stream_wrapper_valid_scheme(file_uri_scheme('public://asdf')), 'Got a valid stream scheme from public://asdf'); |
|
2767 $this->assertFalse(file_stream_wrapper_valid_scheme(file_uri_scheme('foo://asdf')), 'Did not get a valid stream scheme from foo://asdf'); |
|
2768 } |
|
2769 } |