You are here

filefield.test in FileField 6.3

File

tests/filefield.test
View source
<?php

class FileFieldTestCase extends DrupalWebTestCase {
  protected $admin_user;

  /**
   * Implementation of setUp().
   */
  function setUp() {

    // Views is included here just so that it doesn't whine when CCK tries to
    // clear the caches.
    $modules = array_merge(func_get_args(), array(
      'content',
      'filefield',
      'filefield_meta',
      'getid3',
      'mimedetect',
      'token',
      'views',
    ));
    call_user_func_array(array(
      'parent',
      'setUp',
    ), $modules);

    // Create and login user
    $this->admin_user = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer site configuration',
      'administer content types',
      'administer nodes',
      'administer files',
    ));
    $this
      ->drupalLogin($this->admin_user);
  }

  /**
   * Get a sample file of the specified type.
   */
  function getTestFile($type, $size = NULL) {

    // Get a file to upload.
    $file = current($this
      ->drupalGetTestFiles($type, $size));

    // SimpleTest files incorrectly use "filename" instead of "filepath".
    $file->filepath = $file->filename;
    $file->filename = basename($file->filepath);
    $file->filesize = filesize($file->filepath);
    return $file;
  }

  /**
   * Create a new file field.
   *
   * @param $name
   *   The name of the new field (all lowercase), exclude the "field_" prefix.
   * @param $type
   *   The node type that this field will be added to.
   * @param $field_options
   *   A list of field options that will be added to the defaults.
   * @param $widget_options
   *   A list of widget options that will be added to the widget defaults.
   */
  function createFileField($name, $type, $field_options = array(), $widget_options = array()) {
    module_load_include('inc', 'content', 'includes/content.crud');
    $field = array(
      'label' => $name,
      'field_name' => $name,
      'type' => 'filefield',
      'widget_type' => 'filefield_widget',
      'weight' => 0,
      'parent' => 0,
      'type_name' => $type,
      'list_field' => 0,
      'list_default' => 1,
      'description_field' => 0,
    );
    $field = array_merge($field, $field_options);
    $field = content_field_instance_create($field);
    $widget = array(
      'type' => 'filefield_widget',
      'file_extensions' => '',
    );
    $field['widget'] = array_merge($field['widget'], $widget, $widget_options);
    $field = content_field_instance_update($field);
    return $field;
  }

  /**
   * Update an existing FileField with new settings.
   */
  function updateFileField($name, $type, $field_options = array(), $widget_options = array()) {
    $field = content_fields($name, $type);
    $field = array_merge($field, $field_options);
    $field['widget'] = array_merge($field['widget'], $widget_options);
    return content_field_instance_update($field);
  }

  /**
   * Upload a file to a node.
   */
  function uploadNodeFile($file, $field, $nid_or_type, $new_revision = TRUE) {
    $field_name = $field['field_name'];
    $edit = array(
      'title' => $this
        ->randomName(),
      'revision' => (string) (int) $new_revision,
    );
    if (is_numeric($nid_or_type)) {
      $node = node_load($nid_or_type);
      $delta = isset($node->{$field_name}) ? count($node->{$field_name}) : 0;
      $edit['files[' . $field_name . '_' . $delta . ']'] = realpath($file->filepath);
      $this
        ->drupalPost('node/' . $nid_or_type . '/edit', $edit, t('Save'));
    }
    else {
      $delta = '0';
      $edit['files[' . $field_name . '_' . $delta . ']'] = realpath($file->filepath);
      $type = str_replace('_', '-', $nid_or_type);
      $this
        ->drupalPost('node/add/' . $type, $edit, t('Save'));
    }
    $matches = array();
    preg_match('/node\\/([0-9]+)/', $this
      ->getUrl(), $matches);
    $nid = isset($matches[1]) ? $matches[1] : FALSE;

    // Edit the node and add a description if possible.
    if ($nid && $field['description_field']) {
      $edit = array(
        'revision' => 0,
        $field_name . '[' . $delta . '][data][description]' => $this
          ->randomString(),
      );
      $this
        ->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
    }
    return $nid;
  }

  /**
   * Remove a file from a node.
   *
   * Note that if replacing a file, it must first be removed then added again.
   */
  function removeNodeFile($nid, $new_revision = TRUE) {
    $edit = array(
      'revision' => (string) (int) $new_revision,
    );
    $this
      ->drupalPost('node/' . $nid . '/edit', array(), t('Remove'));
    $this
      ->drupalPost(NULL, $edit, t('Save'));
  }

  /**
   * Replace a file within a node.
   */
  function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) {
    $edit = array(
      'files[' . $field_name . '_0]' => realpath($file->filepath),
      'revision' => (string) (int) $new_revision,
    );
    $this
      ->drupalPost('node/' . $nid . '/edit', array(), t('Remove'));
    $this
      ->drupalPost(NULL, $edit, t('Save'));
  }

  /**
   * Assert that a file exists physically on disk.
   */
  function assertFileExists($file, $message = NULL) {
    $message = isset($message) ? $message : t('File %file exists on the disk.', array(
      '%file' => $file['filepath'],
    ));
    $this
      ->assertTrue(is_file($file['filepath']), $message);
  }

  /**
   * Assert that a file exists in the database.
   */
  function assertFileEntryExists($file, $message = NULL) {
    module_load_include('inc', 'filefield', 'field_file');
    $db_file = field_file_load($file['fid'], TRUE);
    $message = isset($message) ? $message : t('File %file exists in database at the correct path.', array(
      '%file' => $file['filepath'],
    ));
    $this
      ->assertEqual($db_file['filepath'], $file['filepath'], $message);
  }

  /**
   * Assert that a file does not exist on disk.
   */
  function assertFileNotExists($file, $message = NULL) {
    $message = isset($message) ? $message : t('File %file exists on the disk.', array(
      '%file' => $file['filepath'],
    ));
    $this
      ->assertFalse(is_file($file['filepath']), $message);
  }

  /**
   * Assert that a file does not exist in the database.
   */
  function assertFileEntryNotExists($file, $message) {
    module_load_include('inc', 'filefield', 'field_file');
    $message = isset($message) ? $message : t('File %file exists in database at the correct path.', array(
      '%file' => $file['filepath'],
    ));
    $this
      ->assertFalse(field_file_load($file['fid'], TRUE), $message);
  }

}

/**
 * Test class to test file handling with node revisions.
 */
class FileFieldRevisionTestCase extends FileFieldTestCase {
  function getInfo() {
    return array(
      'name' => t('FileField revision test'),
      'description' => t('Test creating and deleting revisions with files attached.'),
      'group' => t('FileField'),
    );
  }

  /**
   * Test creating multiple revisions of a node and managing the attached files.
   *
   * Expected behaviors:
   *  - Adding a new revision will make another entry in the field table, but
   *    the original file will not be duplicated.
   *  - Deleting a revision should not delete the original file if the file
   *    is in use by another revision.
   *  - When the last revision that uses a file is deleted, the original file
   *    should be deleted also.
   */
  function testRevisions() {
    $field_name = 'field_' . strtolower($this
      ->randomName());
    $type = $this
      ->drupalCreateContentType();
    $field_options = array(
      'description_field' => '1',
    );
    $field = $this
      ->createFileField($field_name, $type->name, $field_options);
    $test_file = $this
      ->getTestFile('text');

    // Create a new node with the uploaded file.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);

    // Check that the file exists on disk and in the database.
    $node = node_load($nid, NULL, TRUE);
    $node_file_r1 = $node->{$field['field_name']}[0];
    $node_vid_r1 = $node->vid;
    $this
      ->assertFileExists($node_file_r1, t('New file saved to disk on node creation.'));
    $this
      ->assertFileEntryExists($node_file_r1, t('File entry exists in database on node creation.'));

    // Upload another file to the same node in a new revision.
    $this
      ->replaceNodeFile($test_file, $field_name, $nid);
    $node = node_load($nid, NULL, TRUE);
    $node_file_r2 = $node->{$field['field_name']}[0];
    $node_vid_r2 = $node->vid;
    $this
      ->assertFileExists($node_file_r2, t('Replacement file exists on disk after creating new revision.'));
    $this
      ->assertFileEntryExists($node_file_r2, t('Replacement file entry exists in database after creating new revision.'));

    // Check that the original file is still in place on the first revision.
    $node = node_load($nid, $node_vid_r1, TRUE);
    $this
      ->assertEqual($node_file_r1, $node->{$field['field_name']}[0], t('Original file still in place after replacing file in new revision.'));
    $this
      ->assertFileExists($node_file_r1, t('Original file still in place after replacing file in new revision.'));
    $this
      ->assertFileEntryExists($node_file_r1, t('Original file entry still in place after replacing file in new revision'));

    // Save a new version of the node without any changes.
    // Check that the file is still the same as the previous revision.
    $this
      ->drupalPost('node/' . $nid . '/edit', array(
      'revision' => '1',
    ), t('Save'));
    $node = node_load($nid, NULL, TRUE);
    $node_file_r3 = $node->{$field['field_name']}[0];
    $node_vid_r3 = $node->vid;

    // FileField Meta's extensive meta data can be difficult to match up exactly
    // (mostly differences between strings and integers). Just compare the
    // descriptions.
    $node_file_r2['data'] = array(
      'description' => $node_file_r2['data']['description'],
    );
    $node_file_r3['data'] = array(
      'description' => $node_file_r3['data']['description'],
    );
    $this
      ->assertEqual($node_file_r2, $node_file_r3, t('Previous revision file still in place after creating a new revision without a new file.'));

    // Revert to the first revision and check that the original file is active.
    $this
      ->drupalPost('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', array(), t('Revert'));
    $node = node_load($nid, NULL, TRUE);
    $node_file_r4 = $node->{$field['field_name']}[0];
    $node_vid_r4 = $node->vid;
    $this
      ->assertEqual($node_file_r1, $node_file_r4, t('Original revision file still in place after reverting to the original revision.'));

    // Delete the second revision and check that the file is kept (since it is
    // still being used by the third revision).
    $this
      ->drupalPost('node/' . $nid . '/revisions/' . $node_vid_r2 . '/delete', array(), t('Delete'));
    $this
      ->assertFileExists($node_file_r3, t('Second file is still available after deleting second revision, since it is being used by the third revision.'));
    $this
      ->assertFileEntryExists($node_file_r3, t('Second file entry is still available after deleting second revision, since it is being used by the third revision.'));

    // Delete the third revision and check that the file is deleted also.
    $this
      ->drupalPost('node/' . $nid . '/revisions/' . $node_vid_r3 . '/delete', array(), t('Delete'));
    $this
      ->assertFileNotExists($node_file_r3, t('Second file is now deleted after deleting third revision, since it is no longer being used by any other nodes.'));
    $this
      ->assertFileEntryNotExists($node_file_r3, t('Second file entry is now deleted after deleting third revision, since it is no longer being used by any other nodes.'));

    // Delete the entire node and check that the original file is deleted.
    $this
      ->drupalPost('node/' . $nid . '/delete', array(), t('Delete'));
    $this
      ->assertFileNotExists($node_file_r1, t('Original file is deleted after deleting the entire node with two revisions remaining.'));
    $this
      ->assertFileEntryNotExists($node_file_r1, t('Original file entry is deleted after deleting the entire node with two revisions remaining.'));
  }

}

/**
 * Test class to check that formatters are working properly.
 */
class FileFieldDisplayTestCase extends FileFieldTestCase {
  function getInfo() {
    return array(
      'name' => t('FileField display tests'),
      'description' => t('Test the display of file fields in node and views.'),
      'group' => t('FileField'),
    );
  }

  /**
   * Test normal formatter display on node display.
   */
  function testNodeDisplay() {
    $field_name = 'field_' . strtolower($this
      ->randomName());
    $type = $this
      ->drupalCreateContentType();
    $field_options = array(
      'description_field' => '1',
      'list_field' => '1',
      'list_default' => '1',
    );
    $field = $this
      ->createFileField($field_name, $type->name, $field_options);
    $test_file = $this
      ->getTestFile('text');

    // Create a new node with the uploaded file.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);
    $this
      ->drupalGet('node/' . $nid);

    // Check that the default formatter is displaying with the file name.
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $default_output = theme('filefield_file', $node_file);
    $this
      ->assertRaw($default_output, t('Default formatter displaying correctly on full node view.'));

    // Turn the "list" option off and check that the file is no longer listed.
    $edit = array(
      $field['field_name'] . '[0][list]' => FALSE,
    );
    $this
      ->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
    $this
      ->assertNoRaw($default_output, t('Field is hidden when "list" option is unchecked.'));
  }

}

/**
 * Test class to check for various validations.
 */
class FileFieldValidateTestCase extends FileFieldTestCase {
  protected $field;
  protected $node_type;
  function getInfo() {
    return array(
      'name' => t('FileField validation tests'),
      'description' => t('Tests validation functions such as file type, max file size, max size per node, and required.'),
      'group' => t('FileField'),
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    $modules = array_merge(func_get_args(), array(
      'content',
      'filefield',
      'filefield_meta',
      'getid3',
      'mimedetect',
      'token',
      'views',
    ));
    call_user_func_array(array(
      'parent',
      'setUp',
    ), $modules);
    $this->node_type = $this
      ->drupalCreateContentType();
    $this->node_type->url_name = str_replace('_', '-', $this->node_type->name);
    $field_name = 'field_' . strtolower($this
      ->randomName());
    $this->field = $this
      ->createFileField($field_name, $this->node_type->name);
  }

  /**
   * Test required property on file fields.
   */
  function testRequired() {
    $type = $this->node_type;
    $field = $this->field;

    // Make our field required.
    $this
      ->updateFileField($field['field_name'], $type->name, array(
      'required' => '1',
    ));
    $test_file = $this
      ->getTestFile('image');

    // Try to post a new node without uploading a file.
    $edit = array(
      'title' => $this
        ->randomName(),
    );
    $this
      ->drupalPost('node/add/' . $type->url_name, $edit, t('Save'));
    $this
      ->assertRaw(t('%title field is required.', array(
      '%title' => $field['widget']['label'],
    )), t('Node save failed when required file field was empty.'));

    // Create a new node with the uploaded file.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading to the required field.'));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading to the required field.'));

    // Try again with a multiple value field.
    $this
      ->updateFileField($field['field_name'], $type->name, array(
      'multiple' => '0',
      'required' => '1',
    ));

    // Try to post a new node without uploading a file in the multivalue field.
    $edit = array(
      'title' => $this
        ->randomName(),
    );
    $this
      ->drupalPost('node/add/' . $type->url_name, $edit, t('Save'));
    $this
      ->assertRaw(t('%title field is required.', array(
      '%title' => $field['widget']['label'],
    )), t('Node save failed when required multiple value file field was empty.'));

    // Create a new node with the uploaded file into the multivalue field.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading to the required multiple value field.'));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading to the required multipel value field.'));

    // Set the field back to not required.
    $this
      ->updateFileField($field['field_name'], $type->name, array(
      'multiple' => '0',
      'required' => '1',
    ));
  }

  /**
   * Test the max file size validator.
   */
  function testFileMaxSize() {
    $type = $this->node_type;
    $field = $this->field;
    $small_file = $this
      ->getTestFile('text', 131072);

    // 128KB.
    $large_file = $this
      ->getTestFile('text', 1310720);

    // 1.2MB
    // Test uploading both a large and small file with different increments.
    $sizes = array(
      '1M' => 1048576,
      '1024K' => 1048576,
      '1048576' => 1048576,
    );
    foreach ($sizes as $max_filesize_per_file => $file_limit) {

      // Set the max file upload size.
      $this
        ->updateFileField($field['field_name'], $type->name, array(), array(
        'max_filesize_per_file' => $max_filesize_per_file,
      ));

      // Create a new node with the small file, which should pass.
      $nid = $this
        ->uploadNodeFile($small_file, $field, $type->name);
      $node = node_load($nid, NULL, TRUE);
      $node_file = $node->{$field['field_name']}[0];
      $this
        ->assertFileExists($node_file, t('File exists after uploading a file (%filesize) under the max limit (%maxsize).', array(
        '%filesize' => format_size($small_file->filesize),
        '%maxsize' => $max_filesize_per_file,
      )));
      $this
        ->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) under the max limit (%maxsize).', array(
        '%filesize' => format_size($small_file->filesize),
        '%maxsize' => $max_filesize_per_file,
      )));

      // Check that uploading the large file fails (1M limit).
      $nid = $this
        ->uploadNodeFile($large_file, $field, $type->name);
      $error_message = t('The file is %filesize exceeding the maximum file size of %maxsize.', array(
        '%filesize' => format_size($large_file->filesize),
        '%maxsize' => format_size($file_limit),
      ));
      $this
        ->assertRaw($error_message, t('Node save failed when file (%filesize) exceeded the max upload size (%maxsize).', array(
        '%filesize' => format_size($large_file->filesize),
        '%maxsize' => $max_filesize_per_file,
      )));
    }

    // Turn off the max filesize.
    $this
      ->updateFileField($field['field_name'], $type->name, array(), array(
      'max_filesize_per_file' => '',
    ));

    // Upload the big file successfully.
    $nid = $this
      ->uploadNodeFile($large_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading a file (%filesize) with no max limit.', array(
      '%filesize' => format_size($large_file->filesize),
    )));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) with no max limit.', array(
      '%filesize' => format_size($large_file->filesize),
    )));
  }

  /**
   * Test the max file size per node validator.
   */
  function testNodeMaxSize() {
    $type = $this->node_type;
    $field = $this->field;
    $small_file = $this
      ->getTestFile('text', 131072);

    // 128KB.
    $large_file = $this
      ->getTestFile('text', 1310720);

    // 1.2MB
    // Set the max file upload size.
    $max_node_limit = '256K';
    $file_limit = 262144;
    $this
      ->updateFileField($field['field_name'], $type->name, array(
      'multiple' => '1',
    ), array(
      'max_filesize_per_node' => $max_node_limit,
    ));

    // Create a new node with the small file, which should pass.
    $nid = $this
      ->uploadNodeFile($small_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading a file (%filesize) under the max node limit (%maxsize).', array(
      '%filesize' => format_size($small_file->filesize),
      '%maxsize' => $max_node_limit,
    )));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) under the max node limit (%maxsize).', array(
      '%filesize' => format_size($small_file->filesize),
      '%maxsize' => $max_node_limit,
    )));

    // Add a second file to the same node which should pass.
    $nid = $this
      ->uploadNodeFile($small_file, $field, $nid);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading a file (%filesize) under the max node limit (%maxsize).', array(
      '%filesize' => format_size($small_file->filesize),
      '%maxsize' => $max_node_limit,
    )));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) under the max node limit (%maxsize).', array(
      '%filesize' => format_size($small_file->filesize),
      '%maxsize' => $max_node_limit,
    )));

    // Add a third file to the same node which should fail.
    $nid = $this
      ->uploadNodeFile($small_file, $field, $nid);
    $error_message = t('exceeds field settings of %msize.', array(
      '%msize' => format_size($file_limit),
    ));
    $this
      ->assertRaw($error_message, t('File not uploaded as the file (%filesize) exceeds the max node limit (%maxsize).', array(
      '%filesize' => format_size($small_file->filesize),
      '%maxsize' => $max_node_limit,
    )));

    // Check that uploading the large file fails (1M limit).
    $nid = $this
      ->uploadNodeFile($large_file, $field, $type->name);
    $error_message = t('exceeds field settings of %msize.', array(
      '%msize' => format_size($file_limit),
    ));
    $this
      ->assertRaw($error_message, t('File not uploaded as the file (%filesize) exceeds the max node limit (%maxsize).', array(
      '%filesize' => format_size($large_file->filesize),
      '%maxsize' => $max_node_limit,
    )));

    // Turn off the max filesize per node.
    $this
      ->updateFileField($field['field_name'], $type->name, array(
      'multiple' => '0',
    ), array(
      'max_filesize_per_node' => '',
    ));
  }

  /**
   * Test the file extension, do additional checks if mimedetect is installed.
   */
  function testFileExtension() {
    $type = $this->node_type;
    $field = $this->field;

    // Setup files for extension checking.
    $test_file = $this
      ->getTestFile('image');
    preg_match('/(?<=\\.)[^\\.]*$/', $test_file->filename, $matches);
    $extention = current($matches);
    $wrong_extension_file = drupal_clone($test_file);
    $wrong_extension_file->filename = str_replace(".{$extention}", '.jpg', $test_file->filename);
    $wrong_extension_file->filepath = file_directory_path() . '/' . $wrong_extension_file->filename;
    $original_path = $test_file->filepath;
    file_copy($original_path, $wrong_extension_file->filepath);
    $this
      ->updateFileField($field['field_name'], $type->name, array(), array(
      'file_extensions' => '',
    ));

    // Check that the file can be uploaded with no extension checking.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading a file with no extension checking.'));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading a file with no extension checking.'));

    // Enable extension checking.
    $this
      ->updateFileField($field['field_name'], $type->name, array(), array(
      'file_extensions' => "txt png jpg {$extention}",
    ));

    // Check that the file can be uploaded with extension checking.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertFileExists($node_file, t('File exists after uploading a file with extension checking.'));
    $this
      ->assertFileEntryExists($node_file, t('File entry exists after uploading a file with extension checking.'));

    // Check that a mismatched extension cannot be uploaded.
    $mimedetect = FALSE;
    if (module_exists('mimedetect')) {
      $mimedetect = TRUE;
      module_load_include('install', 'mimedetect');
      if (!extension_loaded('fileinfo')) {
        variable_set('mimedetect_enable_file_binary', 1);
      }
      $requirements = mimedetect_requirements('runtime');
      foreach ($requirements as $requirement) {
        if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
          $mimedetect = FALSE;
        }
      }
    }
    if ($mimedetect) {
      $this
        ->uploadNodeFile($wrong_extension_file, $field, $type->name);
      $error_pattern = "/The file contents \\([a-z\\-\\/]+\\) do not match its extension \\([a-z]+\\)\\./";
      $this
        ->assertPattern($error_pattern, t('File prevented from uploading because its extension does not match its content.'));
    }
    else {
      $this
        ->assertTrue(TRUE, t('Mime type checking and extension spoofing skipped because the mimedetect module is not available.'));
    }

    // Disable the extension checking.
    $this
      ->updateFileField($field['field_name'], $type->name, array(), array(
      'file_extensions' => '',
    ));
  }

}

/**
 * Test class to check that files are uploaded to proper locations.
 */
class FileFieldPathTestCase extends FileFieldTestCase {
  function getInfo() {
    return array(
      'name' => t('FileField file path tests'),
      'description' => t('Test that files are uploaded to the proper location, extra testing if Token module is available.'),
      'group' => t('FileField'),
    );
  }

  /**
   * Test normal formatter display on node display.
   */
  function testUploadPath() {
    $field_name = 'field_' . strtolower($this
      ->randomName());
    $type = $this
      ->drupalCreateContentType();
    $field = $this
      ->createFileField($field_name, $type->name);
    $test_file = $this
      ->getTestFile('text');

    // Create a new node.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);

    // Check that the file was uploaded to the file root.
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertPathMatch(file_directory_path() . '/' . $test_file->filename, $node_file['filepath'], t('The file %file was uploaded to the correct path.', array(
      '%file' => $node_file['filepath'],
    )));

    // Change the path to contain multiple subdirectories.
    $field = $this
      ->updateFileField($field['field_name'], $type->name, array(), array(
      'file_path' => 'foo/bar/baz',
    ));

    // Upload a new file into the subdirectories.
    $nid = $this
      ->uploadNodeFile($test_file, $field, $type->name);

    // Check that the file was uploaded into the subdirectory.
    $node = node_load($nid, NULL, TRUE);
    $node_file = $node->{$field['field_name']}[0];
    $this
      ->assertPathMatch(file_directory_path() . '/foo/bar/baz/' . $test_file->filename, $node_file['filepath'], t('The file %file was uploaded to the correct path.', array(
      '%file' => $node_file['filepath'],
    )));

    // Check the path when used with tokens.
    if (module_exists('token')) {

      // Change the path to contain multiple token directories.
      $field = $this
        ->updateFileField($field['field_name'], $type->name, array(), array(
        'file_path' => '[uid]/[user-raw]',
      ));

      // Upload a new file into the token subdirectories.
      $nid = $this
        ->uploadNodeFile($test_file, $field, $type->name);

      // Check that the file was uploaded into the subdirectory.
      $node = node_load($nid, NULL, TRUE);
      $node_file = $node->{$field['field_name']}[0];
      $subdirectory = token_replace('[uid]/[user-raw]', 'user', $this->admin_user);
      $this
        ->assertPathMatch(file_directory_path() . '/' . $subdirectory . '/' . $test_file->filename, $node_file['filepath'], t('The file %file was uploaded to the correct path with token replacements.', array(
        '%file' => $node_file['filepath'],
      )));
    }
    else {
      $this
        ->assertTrue(TRUE, t('File path token test skipped because the Token module is not available.'));
    }
  }

  /**
   * A loose assertion to check that a file is uploaded to the right location.
   *
   * @param $expected_path
   *   The location where the file is expected to be uploaded. Duplicate file
   *   names to not need to be taken into account.
   * @param $actual_path
   *   Where the file was actually uploaded.
   * @param $message
   *   The message to display with this assertion.
   */
  function assertPathMatch($expected_path, $actual_path, $message) {

    // Strip off the extension of the expected path to allow for _0, _1, etc.
    // suffixes when the file hits a duplicate name.
    $pos = strrpos($expected_path, '.');
    $base_path = substr($expected_path, 0, $pos);
    $extension = substr($expected_path, $pos + 1);
    $result = preg_match('/' . preg_quote($base_path, '/') . '(_[0-9]+)?\\.' . preg_quote($extension, '/') . '/', $actual_path);
    $this
      ->assertTrue($result, $message);
  }

}

Classes

Namesort descending Description
FileFieldDisplayTestCase Test class to check that formatters are working properly.
FileFieldPathTestCase Test class to check that files are uploaded to proper locations.
FileFieldRevisionTestCase Test class to test file handling with node revisions.
FileFieldTestCase
FileFieldValidateTestCase Test class to check for various validations.