cms/drupal/modules/simpletest/tests/file.test
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     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 }