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
|
}
|