filefield.test 27.2 KB
Newer Older
1 2 3 4
<?php
// $Id$

class FileFieldTestCase extends DrupalWebTestCase {
5 6
  protected $admin_user;

7 8 9 10 11 12
  /**
   * Implementation of setUp().
   */
  function setUp() {
    // Views and ImageCache are included here just so that they don't whine
    // when CCK tries to clear thier caches.
13
    $modules = array_merge(func_get_args(), array('content', 'filefield', 'mimedetect', 'token', 'views'));
14
    call_user_func_array(array($this, 'parent::setUp'), $modules);
15 16

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

  /**
   * Get a sample file of the specified type.
   */
24
  function getTestFile($type, $size = NULL) {
25
    // Get a file to upload.
26
    $file = current($this->drupalGetTestFiles($type, $size));
27 28 29

    // SimpleTest files incorrectly use "filename" instead of "filepath".
    $file->filepath = $file->filename;
30 31
    $file->filename = basename($file->filepath);
    $file->filesize = filesize($file->filepath);
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

    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,
52
      'field_name' => $name,
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
      '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',
68
      'file_extensions' => '',
69 70 71 72 73 74 75 76 77 78 79
    );

    $field['widget'] = array_merge($field['widget'], $widget, $widget_options);
    $field = content_field_instance_update($field);

    return $field;
  }

  /**
   * Update an existing FileField with new settings.
   */
80 81
  function updateFileField($name, $type, $field_options = array(), $widget_options = array()) {
    $field = content_fields($name, $type);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    $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_name, $nid_or_type, $new_revision = TRUE) {
    $edit = array(
      'title' => $this->randomName(),
      'revision' => (string) (int) $new_revision,
    );

    if (is_numeric($nid_or_type)) {
98 99 100
      $node = node_load($nid_or_type);
      $delta = isset($node->$field_name) ? count($node->$field_name) : 0;
      $edit['files[' . $field_name . '_' . $delta . ']'] = realpath($file->filepath);
101 102 103
      $this->drupalPost('node/' . $nid_or_type . '/edit', $edit, t('Save'));
    }
    else {
104
      $edit['files[' . $field_name . '_0]'] = realpath($file->filepath);
105 106 107 108 109 110
      $type = str_replace('_', '-', $nid_or_type);
      $this->drupalPost('node/add/' . $type, $edit, t('Save'));
    }

    $matches = array();
    preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
quicksketch's avatar
quicksketch committed
111
    return isset($matches[1]) ? $matches[1] : FALSE;
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
  }

  /**
   * 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(
133
      'files[' . $field_name . '_0]' => realpath($file->filepath),
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
      '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() {
201
    $field_name = 'field_' . strtolower($this->randomName());
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    $type = $this->drupalCreateContentType();
    $field = $this->createFileField($field_name, $type->name);

    $test_file = $this->getTestFile('text');

    // Create a new node with the uploaded file.
    $nid = $this->uploadNodeFile($test_file, $field_name, $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;
    $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() {
280
    $field_name = 'field_' . strtolower($this->randomName());
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    $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_name, $type->name);
    $this->drupalGet('node/' . $nid . '/edit');

    // 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.'));

  }
}
308 309 310 311 312

/**
 * Test class to check for various validations.
 */
class FileFieldValidateTestCase extends FileFieldTestCase {
313 314
  protected $field;
  protected $node_type;
315 316 317 318 319 320 321 322 323 324 325 326 327

  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() {
328 329
    $modules = array_merge(func_get_args(), array('content', 'filefield', 'mimedetect', 'token', 'views'));
    call_user_func_array(array($this, 'parent::setUp'), $modules);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

    $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'));

347
    $test_file = $this->getTestFile('image');
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477

    // 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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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['field_name'], $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.
478
    $test_file = $this->getTestFile('image');
479 480
    preg_match('/(?<=\.)[^\.]*$/', $test_file->filename, $matches);
    $extention = current($matches);
481
    $wrong_extension_file = drupal_clone($test_file);
482
    $wrong_extension_file->filename = str_replace(".$extention", '.jpg', $test_file->filename);
483
    $wrong_extension_file->filepath = file_directory_path() .'/'. $wrong_extension_file->filename;
484
    $original_path = $test_file->filepath;
485 486 487 488 489
    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.
490
    $nid = $this->uploadNodeFile($test_file, $field['field_name'], $type->name);
491 492 493 494 495 496
    $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.
497
    $this->updateFileField($field['field_name'], $type->name, array(), array('file_extensions' => "txt png jpg $extention"));
498 499

    // Check that the file can be uploaded with extension checking.
500
    $nid = $this->uploadNodeFile($test_file, $field['field_name'], $type->name);
501 502 503 504 505 506 507 508
    $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.
    if (module_exists('mimedetect')) {
      $this->uploadNodeFile($wrong_extension_file, $field['field_name'], $type->name);
509
      $error_pattern = "/The file contents \([a-z\-\/]+\) do not match its extension \([a-z]+\)\./";
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
      $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_name, $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_name, $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.
562
    if (module_exists('token')) {
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
      // 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_name, $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);
  }
}