cms/drupal/modules/image/image.test
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * Tests for image.module.
       
     6  */
       
     7 
       
     8 /**
       
     9  * TODO: Test the following functions.
       
    10  *
       
    11  * image.effects.inc:
       
    12  *   image_style_generate()
       
    13  *   image_style_create_derivative()
       
    14  *
       
    15  * image.module:
       
    16  *   image_style_load()
       
    17  *   image_style_save()
       
    18  *   image_style_delete()
       
    19  *   image_style_options()
       
    20  *   image_effect_definition_load()
       
    21  *   image_effect_load()
       
    22  *   image_effect_save()
       
    23  *   image_effect_delete()
       
    24  *   image_filter_keyword()
       
    25  */
       
    26 
       
    27 /**
       
    28  * This class provides methods specifically for testing Image's field handling.
       
    29  */
       
    30 class ImageFieldTestCase extends DrupalWebTestCase {
       
    31   protected $admin_user;
       
    32 
       
    33   function setUp() {
       
    34     parent::setUp('image');
       
    35     $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles', 'administer fields'));
       
    36     $this->drupalLogin($this->admin_user);
       
    37   }
       
    38 
       
    39   /**
       
    40    * Create a new image field.
       
    41    *
       
    42    * @param $name
       
    43    *   The name of the new field (all lowercase), exclude the "field_" prefix.
       
    44    * @param $type_name
       
    45    *   The node type that this field will be added to.
       
    46    * @param $field_settings
       
    47    *   A list of field settings that will be added to the defaults.
       
    48    * @param $instance_settings
       
    49    *   A list of instance settings that will be added to the instance defaults.
       
    50    * @param $widget_settings
       
    51    *   A list of widget settings that will be added to the widget defaults.
       
    52    */
       
    53   function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
       
    54     $field = array(
       
    55       'field_name' => $name,
       
    56       'type' => 'image',
       
    57       'settings' => array(),
       
    58       'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
       
    59     );
       
    60     $field['settings'] = array_merge($field['settings'], $field_settings);
       
    61     field_create_field($field);
       
    62 
       
    63     $instance = array(
       
    64       'field_name' => $field['field_name'],
       
    65       'entity_type' => 'node',
       
    66       'label' => $name,
       
    67       'bundle' => $type_name,
       
    68       'required' => !empty($instance_settings['required']),
       
    69       'settings' => array(),
       
    70       'widget' => array(
       
    71         'type' => 'image_image',
       
    72         'settings' => array(),
       
    73       ),
       
    74     );
       
    75     $instance['settings'] = array_merge($instance['settings'], $instance_settings);
       
    76     $instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings);
       
    77     return field_create_instance($instance);
       
    78   }
       
    79 
       
    80   /**
       
    81    * Create a random style.
       
    82    *
       
    83    * @return array
       
    84    *  A list containing the details of the generated image style.
       
    85    */
       
    86   function createRandomStyle() {
       
    87     $style_name = strtolower($this->randomName(10));
       
    88     $style_label = $this->randomString();
       
    89     image_style_save(array('name' => $style_name, 'label' => $style_label));
       
    90     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
    91     return array(
       
    92       'name' => $style_name,
       
    93       'label' => $style_label,
       
    94       'path' => $style_path,
       
    95     );
       
    96   }
       
    97 
       
    98   /**
       
    99    * Upload an image to a node.
       
   100    *
       
   101    * @param $image
       
   102    *   A file object representing the image to upload.
       
   103    * @param $field_name
       
   104    *   Name of the image field the image should be attached to.
       
   105    * @param $type
       
   106    *   The type of node to create.
       
   107    */
       
   108   function uploadNodeImage($image, $field_name, $type) {
       
   109     $edit = array(
       
   110       'title' => $this->randomName(),
       
   111     );
       
   112     $edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri);
       
   113     $this->drupalPost('node/add/' . $type, $edit, t('Save'));
       
   114 
       
   115     // Retrieve ID of the newly created node from the current URL.
       
   116     $matches = array();
       
   117     preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
       
   118     return isset($matches[1]) ? $matches[1] : FALSE;
       
   119   }
       
   120 }
       
   121 
       
   122 /**
       
   123  * Tests the functions for generating paths and URLs for image styles.
       
   124  */
       
   125 class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
       
   126   protected $style_name;
       
   127   protected $image_info;
       
   128   protected $image_filepath;
       
   129 
       
   130   public static function getInfo() {
       
   131     return array(
       
   132       'name' => 'Image styles path and URL functions',
       
   133       'description' => 'Tests functions for generating paths and URLs to image styles.',
       
   134       'group' => 'Image',
       
   135     );
       
   136   }
       
   137 
       
   138   function setUp() {
       
   139     parent::setUp('image_module_test');
       
   140 
       
   141     $this->style_name = 'style_foo';
       
   142     image_style_save(array('name' => $this->style_name, 'label' => $this->randomString()));
       
   143   }
       
   144 
       
   145   /**
       
   146    * Test image_style_path().
       
   147    */
       
   148   function testImageStylePath() {
       
   149     $scheme = 'public';
       
   150     $actual = image_style_path($this->style_name, "$scheme://foo/bar.gif");
       
   151     $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
       
   152     $this->assertEqual($actual, $expected, 'Got the path for a file URI.');
       
   153 
       
   154     $actual = image_style_path($this->style_name, 'foo/bar.gif');
       
   155     $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
       
   156     $this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
       
   157   }
       
   158 
       
   159   /**
       
   160    * Test image_style_url() with a file using the "public://" scheme.
       
   161    */
       
   162   function testImageStyleUrlAndPathPublic() {
       
   163     $this->_testImageStyleUrlAndPath('public');
       
   164   }
       
   165 
       
   166   /**
       
   167    * Test image_style_url() with a file using the "private://" scheme.
       
   168    */
       
   169   function testImageStyleUrlAndPathPrivate() {
       
   170     $this->_testImageStyleUrlAndPath('private');
       
   171   }
       
   172 
       
   173   /**
       
   174    * Test image_style_url() with the "public://" scheme and unclean URLs.
       
   175    */
       
   176    function testImageStylUrlAndPathPublicUnclean() {
       
   177      $this->_testImageStyleUrlAndPath('public', FALSE);
       
   178    }
       
   179 
       
   180   /**
       
   181    * Test image_style_url() with the "private://" schema and unclean URLs.
       
   182    */
       
   183   function testImageStyleUrlAndPathPrivateUnclean() {
       
   184     $this->_testImageStyleUrlAndPath('private', FALSE);
       
   185   }
       
   186 
       
   187   /**
       
   188    * Test image_style_url() with a file URL that has an extra slash in it.
       
   189    */
       
   190   function testImageStyleUrlExtraSlash() {
       
   191     $this->_testImageStyleUrlAndPath('public', TRUE, TRUE);
       
   192   }
       
   193 
       
   194   /**
       
   195    * Test that an invalid source image returns a 404.
       
   196    */
       
   197   function testImageStyleUrlForMissingSourceImage() {
       
   198     $non_existent_uri = 'public://foo.png';
       
   199     $generated_url = image_style_url($this->style_name, $non_existent_uri);
       
   200     $this->drupalGet($generated_url);
       
   201     $this->assertResponse(404, 'Accessing an image style URL with a source image that does not exist provides a 404 error response.');
       
   202   }
       
   203 
       
   204   /**
       
   205    * Test that we do not pass an array to drupal_add_http_header.
       
   206    */
       
   207   function testImageContentTypeHeaders() {
       
   208     $files = $this->drupalGetTestFiles('image');
       
   209     $file = array_shift($files);
       
   210     // Copy the test file to private folder.
       
   211     $private_file = file_copy($file, 'private://', FILE_EXISTS_RENAME);
       
   212     // Tell image_module_test module to return the headers we want to test.
       
   213     variable_set('image_module_test_invalid_headers', $private_file->uri);
       
   214     // Invoke image_style_deliver so it will try to set headers.
       
   215     $generated_url = image_style_url($this->style_name, $private_file->uri);
       
   216     $this->drupalGet($generated_url);
       
   217     variable_del('image_module_test_invalid_headers');
       
   218   }
       
   219 
       
   220   /**
       
   221    * Test image_style_url().
       
   222    */
       
   223   function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
       
   224     // Make the default scheme neither "public" nor "private" to verify the
       
   225     // functions work for other than the default scheme.
       
   226     variable_set('file_default_scheme', 'temporary');
       
   227     variable_set('clean_url', $clean_url);
       
   228 
       
   229     // Create the directories for the styles.
       
   230     $directory = $scheme . '://styles/' . $this->style_name;
       
   231     $status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
       
   232     $this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
       
   233 
       
   234     // Create a working copy of the file.
       
   235     $files = $this->drupalGetTestFiles('image');
       
   236     $file = array_shift($files);
       
   237     $image_info = image_get_info($file->uri);
       
   238     $original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
       
   239     // Let the image_module_test module know about this file, so it can claim
       
   240     // ownership in hook_file_download().
       
   241     variable_set('image_module_test_file_download', $original_uri);
       
   242     $this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.');
       
   243 
       
   244     // Get the URL of a file that has not been generated and try to create it.
       
   245     $generated_uri = image_style_path($this->style_name, $original_uri);
       
   246     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
   247     $generate_url = image_style_url($this->style_name, $original_uri);
       
   248 
       
   249     // Ensure that the tests still pass when the file is generated by accessing
       
   250     // a poorly constructed (but still valid) file URL that has an extra slash
       
   251     // in it.
       
   252     if ($extra_slash) {
       
   253       $modified_uri = str_replace('://', ':///', $original_uri);
       
   254       $this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
       
   255       $generate_url = image_style_url($this->style_name, $modified_uri);
       
   256     }
       
   257 
       
   258     if (!$clean_url) {
       
   259       $this->assertTrue(strpos($generate_url, '?q=') !== FALSE, 'When using non-clean URLS, the system path contains the query string.');
       
   260     }
       
   261     // Add some extra chars to the token.
       
   262     $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
       
   263     $this->assertResponse(403, 'Image was inaccessible at the URL with an invalid token.');
       
   264     // Change the parameter name so the token is missing.
       
   265     $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
       
   266     $this->assertResponse(403, 'Image was inaccessible at the URL with a missing token.');
       
   267 
       
   268     // Check that the generated URL is the same when we pass in a relative path
       
   269     // rather than a URI. We need to temporarily switch the default scheme to
       
   270     // match the desired scheme before testing this, then switch it back to the
       
   271     // "temporary" scheme used throughout this test afterwards.
       
   272     variable_set('file_default_scheme', $scheme);
       
   273     $relative_path = file_uri_target($original_uri);
       
   274     $generate_url_from_relative_path = image_style_url($this->style_name, $relative_path);
       
   275     $this->assertEqual($generate_url, $generate_url_from_relative_path, 'Generated URL is the same regardless of whether it came from a relative path or a file URI.');
       
   276     variable_set('file_default_scheme', 'temporary');
       
   277 
       
   278     // Fetch the URL that generates the file.
       
   279     $this->drupalGet($generate_url);
       
   280     $this->assertResponse(200, 'Image was generated at the URL.');
       
   281     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
   282     $this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.');
       
   283     $generated_image_info = image_get_info($generated_uri);
       
   284     $this->assertEqual($this->drupalGetHeader('Content-Type'), $generated_image_info['mime_type'], 'Expected Content-Type was reported.');
       
   285     $this->assertEqual($this->drupalGetHeader('Content-Length'), $generated_image_info['file_size'], 'Expected Content-Length was reported.');
       
   286     if ($scheme == 'private') {
       
   287       $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
       
   288       $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate', 'Cache-Control header was set to prevent caching.');
       
   289       $this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
       
   290 
       
   291       // Make sure that a second request to the already existing derivate works
       
   292       // too.
       
   293       $this->drupalGet($generate_url);
       
   294       $this->assertResponse(200, 'Image was generated at the URL.');
       
   295 
       
   296       // Make sure that access is denied for existing style files if we do not
       
   297       // have access.
       
   298       variable_del('image_module_test_file_download');
       
   299       $this->drupalGet($generate_url);
       
   300       $this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
       
   301 
       
   302       // Repeat this with a different file that we do not have access to and
       
   303       // make sure that access is denied.
       
   304       $file_noaccess = array_shift($files);
       
   305       $original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME);
       
   306       $generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
       
   307       $this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
       
   308       $generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess);
       
   309 
       
   310       $this->drupalGet($generate_url_noaccess);
       
   311       $this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
       
   312       // Verify that images are not appended to the response. Currently this test only uses PNG images.
       
   313       if (strpos($generate_url, '.png') === FALSE ) {
       
   314         $this->fail('Confirming that private image styles are not appended require PNG file.');
       
   315       }
       
   316       else {
       
   317         // Check for PNG-Signature (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2) in the
       
   318         // response body.
       
   319         $this->assertNoRaw( chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), 'No PNG signature found in the response body.');
       
   320       }
       
   321     }
       
   322     elseif ($clean_url) {
       
   323       // Add some extra chars to the token.
       
   324       $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
       
   325       $this->assertResponse(200, 'Existing image was accessible at the URL with an invalid token.');
       
   326     }
       
   327 
       
   328     // Allow insecure image derivatives to be created for the remainder of this
       
   329     // test.
       
   330     variable_set('image_allow_insecure_derivatives', TRUE);
       
   331 
       
   332     // Create another working copy of the file.
       
   333     $files = $this->drupalGetTestFiles('image');
       
   334     $file = array_shift($files);
       
   335     $image_info = image_get_info($file->uri);
       
   336     $original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
       
   337     // Let the image_module_test module know about this file, so it can claim
       
   338     // ownership in hook_file_download().
       
   339     variable_set('image_module_test_file_download', $original_uri);
       
   340 
       
   341     // Get the URL of a file that has not been generated and try to create it.
       
   342     $generated_uri = image_style_path($this->style_name, $original_uri);
       
   343     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
   344     $generate_url = image_style_url($this->style_name, $original_uri);
       
   345 
       
   346     // Check that the image is accessible even without the security token.
       
   347     $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
       
   348     $this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
       
   349 
       
   350     // Check that a security token is still required when generating a second
       
   351     // image derivative using the first one as a source.
       
   352     $nested_uri = image_style_path($this->style_name, $generated_uri);
       
   353     $nested_url = image_style_url($this->style_name, $generated_uri);
       
   354     $nested_url_with_wrong_token = str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $nested_url);
       
   355     $this->drupalGet($nested_url_with_wrong_token);
       
   356     $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token.');
       
   357     // Check that this restriction cannot be bypassed by adding extra slashes
       
   358     // to the URL.
       
   359     $this->drupalGet(substr_replace($nested_url_with_wrong_token, '//styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
       
   360     $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with an extra forward slash in the URL.');
       
   361     $this->drupalGet(substr_replace($nested_url_with_wrong_token, '/\styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
       
   362     $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with an extra backslash in the URL.');
       
   363     // Make sure the image can still be generated if a correct token is used.
       
   364     $this->drupalGet($nested_url);
       
   365     $this->assertResponse(200, 'Image was accessible when a correct token was provided in the URL.');
       
   366 
       
   367     // Suppress the security token in the URL, then get the URL of a file. Check
       
   368     // that the security token is not present in the URL but that the image is
       
   369     // still accessible.
       
   370     variable_set('image_suppress_itok_output', TRUE);
       
   371     $generate_url = image_style_url($this->style_name, $original_uri);
       
   372     $this->assertIdentical(strpos($generate_url, IMAGE_DERIVATIVE_TOKEN . '='), FALSE, 'The security token does not appear in the image style URL.');
       
   373     $this->drupalGet($generate_url);
       
   374     $this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
       
   375 
       
   376     // Check that requesting a nonexistent image does not create any new
       
   377     // directories in the file system.
       
   378     $directory = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/' . $this->randomName();
       
   379     $this->drupalGet(file_create_url($directory . '/' . $this->randomName()));
       
   380     $this->assertFalse(file_exists($directory), 'New directory was not created in the filesystem when requesting an unauthorized image.');
       
   381   }
       
   382 }
       
   383 
       
   384 /**
       
   385  * Use the image_test.module's mock toolkit to ensure that the effects are
       
   386  * properly passing parameters to the image toolkit.
       
   387  */
       
   388 class ImageEffectsUnitTest extends ImageToolkitTestCase {
       
   389   public static function getInfo() {
       
   390     return array(
       
   391       'name' => 'Image effects',
       
   392       'description' => 'Test that the image effects pass parameters to the toolkit correctly.',
       
   393       'group' => 'Image',
       
   394     );
       
   395   }
       
   396 
       
   397   function setUp() {
       
   398     parent::setUp('image_module_test');
       
   399     module_load_include('inc', 'image', 'image.effects');
       
   400   }
       
   401 
       
   402   /**
       
   403    * Test the image_resize_effect() function.
       
   404    */
       
   405   function testResizeEffect() {
       
   406     $this->assertTrue(image_resize_effect($this->image, array('width' => 1, 'height' => 2)), 'Function returned the expected value.');
       
   407     $this->assertToolkitOperationsCalled(array('resize'));
       
   408 
       
   409     // Check the parameters.
       
   410     $calls = image_test_get_all_calls();
       
   411     $this->assertEqual($calls['resize'][0][1], 1, 'Width was passed correctly');
       
   412     $this->assertEqual($calls['resize'][0][2], 2, 'Height was passed correctly');
       
   413   }
       
   414 
       
   415   /**
       
   416    * Test the image_scale_effect() function.
       
   417    */
       
   418   function testScaleEffect() {
       
   419     // @todo: need to test upscaling.
       
   420     $this->assertTrue(image_scale_effect($this->image, array('width' => 10, 'height' => 10)), 'Function returned the expected value.');
       
   421     $this->assertToolkitOperationsCalled(array('resize'));
       
   422 
       
   423     // Check the parameters.
       
   424     $calls = image_test_get_all_calls();
       
   425     $this->assertEqual($calls['resize'][0][1], 10, 'Width was passed correctly');
       
   426     $this->assertEqual($calls['resize'][0][2], 5, 'Height was based off aspect ratio and passed correctly');
       
   427   }
       
   428 
       
   429   /**
       
   430    * Test the image_crop_effect() function.
       
   431    */
       
   432   function testCropEffect() {
       
   433     // @todo should test the keyword offsets.
       
   434     $this->assertTrue(image_crop_effect($this->image, array('anchor' => 'top-1', 'width' => 3, 'height' => 4)), 'Function returned the expected value.');
       
   435     $this->assertToolkitOperationsCalled(array('crop'));
       
   436 
       
   437     // Check the parameters.
       
   438     $calls = image_test_get_all_calls();
       
   439     $this->assertEqual($calls['crop'][0][1], 0, 'X was passed correctly');
       
   440     $this->assertEqual($calls['crop'][0][2], 1, 'Y was passed correctly');
       
   441     $this->assertEqual($calls['crop'][0][3], 3, 'Width was passed correctly');
       
   442     $this->assertEqual($calls['crop'][0][4], 4, 'Height was passed correctly');
       
   443   }
       
   444 
       
   445   /**
       
   446    * Test the image_scale_and_crop_effect() function.
       
   447    */
       
   448   function testScaleAndCropEffect() {
       
   449     $this->assertTrue(image_scale_and_crop_effect($this->image, array('width' => 5, 'height' => 10)), 'Function returned the expected value.');
       
   450     $this->assertToolkitOperationsCalled(array('resize', 'crop'));
       
   451 
       
   452     // Check the parameters.
       
   453     $calls = image_test_get_all_calls();
       
   454     $this->assertEqual($calls['crop'][0][1], 7.5, 'X was computed and passed correctly');
       
   455     $this->assertEqual($calls['crop'][0][2], 0, 'Y was computed and passed correctly');
       
   456     $this->assertEqual($calls['crop'][0][3], 5, 'Width was computed and passed correctly');
       
   457     $this->assertEqual($calls['crop'][0][4], 10, 'Height was computed and passed correctly');
       
   458   }
       
   459 
       
   460   /**
       
   461    * Test the image_desaturate_effect() function.
       
   462    */
       
   463   function testDesaturateEffect() {
       
   464     $this->assertTrue(image_desaturate_effect($this->image, array()), 'Function returned the expected value.');
       
   465     $this->assertToolkitOperationsCalled(array('desaturate'));
       
   466 
       
   467     // Check the parameters.
       
   468     $calls = image_test_get_all_calls();
       
   469     $this->assertEqual(count($calls['desaturate'][0]), 1, 'Only the image was passed.');
       
   470   }
       
   471 
       
   472   /**
       
   473    * Test the image_rotate_effect() function.
       
   474    */
       
   475   function testRotateEffect() {
       
   476     // @todo: need to test with 'random' => TRUE
       
   477     $this->assertTrue(image_rotate_effect($this->image, array('degrees' => 90, 'bgcolor' => '#fff')), 'Function returned the expected value.');
       
   478     $this->assertToolkitOperationsCalled(array('rotate'));
       
   479 
       
   480     // Check the parameters.
       
   481     $calls = image_test_get_all_calls();
       
   482     $this->assertEqual($calls['rotate'][0][1], 90, 'Degrees were passed correctly');
       
   483     $this->assertEqual($calls['rotate'][0][2], 0xffffff, 'Background color was passed correctly');
       
   484   }
       
   485 
       
   486   /**
       
   487    * Test image effect caching.
       
   488    */
       
   489   function testImageEffectsCaching() {
       
   490     $image_effect_definitions_called = &drupal_static('image_module_test_image_effect_info_alter');
       
   491 
       
   492     // First call should grab a fresh copy of the data.
       
   493     $effects = image_effect_definitions();
       
   494     $this->assertTrue($image_effect_definitions_called === 1, 'image_effect_definitions() generated data.');
       
   495 
       
   496     // Second call should come from cache.
       
   497     drupal_static_reset('image_effect_definitions');
       
   498     drupal_static_reset('image_module_test_image_effect_info_alter');
       
   499     $cached_effects = image_effect_definitions();
       
   500     $this->assertTrue(is_null($image_effect_definitions_called), 'image_effect_definitions() returned data from cache.');
       
   501 
       
   502     $this->assertTrue($effects == $cached_effects, 'Cached effects are the same as generated effects.');
       
   503   }
       
   504 }
       
   505 
       
   506 /**
       
   507  * Tests the administrative user interface.
       
   508  */
       
   509 class ImageAdminUiTestCase extends ImageFieldTestCase {
       
   510   public static function getInfo() {
       
   511     return array(
       
   512       'name' => 'Administrative user interface',
       
   513       'description' => 'Tests the forms used in the administrative user interface.',
       
   514       'group' => 'Image',
       
   515     );
       
   516   }
       
   517 
       
   518   function setUp() {
       
   519     parent::setUp(array('image'));
       
   520   }
       
   521 
       
   522   /**
       
   523    * Test if the help text is available on the add effect form.
       
   524    */
       
   525   function testAddEffectHelpText() {
       
   526     // Create a random image style.
       
   527     $style = $this->createRandomStyle();
       
   528 
       
   529     // Open the add effect form and check for the help text.
       
   530     $this->drupalGet($style['path'] . '/add/image_crop');
       
   531     $this->assertText(t('Cropping will remove portions of an image to make it the specified dimensions.'), 'The image style effect help text was displayed on the add effect page.');
       
   532   }
       
   533 
       
   534   /**
       
   535    * Test if the help text is available on the edit effect form.
       
   536    */
       
   537   function testEditEffectHelpText() {
       
   538     // Create a random image style.
       
   539     $random_style = $this->createRandomStyle();
       
   540 
       
   541     // Add the crop effect to the image style.
       
   542     $edit = array();
       
   543     $edit['data[width]'] = 20;
       
   544     $edit['data[height]'] = 20;
       
   545     $this->drupalPost($random_style['path'] . '/add/image_crop', $edit, t('Add effect'));
       
   546 
       
   547     // Open the edit effect form and check for the help text.
       
   548     drupal_static_reset('image_styles');
       
   549     $style = image_style_load($random_style['name']);
       
   550 
       
   551     foreach ($style['effects'] as $ieid => $effect) {
       
   552       $this->drupalGet($random_style['path'] . '/effects/' . $ieid);
       
   553       $this->assertText(t('Cropping will remove portions of an image to make it the specified dimensions.'), 'The image style effect help text was displayed on the edit effect page.');
       
   554     }
       
   555   }
       
   556 }
       
   557 
       
   558 /**
       
   559  * Tests creation, deletion, and editing of image styles and effects.
       
   560  */
       
   561 class ImageAdminStylesUnitTest extends ImageFieldTestCase {
       
   562 
       
   563   public static function getInfo() {
       
   564     return array(
       
   565       'name' => 'Image styles and effects UI configuration',
       
   566       'description' => 'Tests creation, deletion, and editing of image styles and effects at the UI level.',
       
   567       'group' => 'Image',
       
   568     );
       
   569   }
       
   570 
       
   571   /**
       
   572    * Given an image style, generate an image.
       
   573    */
       
   574   function createSampleImage($style) {
       
   575     static $file_path;
       
   576 
       
   577     // First, we need to make sure we have an image in our testing
       
   578     // file directory. Copy over an image on the first run.
       
   579     if (!isset($file_path)) {
       
   580       $files = $this->drupalGetTestFiles('image');
       
   581       $file = reset($files);
       
   582       $file_path = file_unmanaged_copy($file->uri);
       
   583     }
       
   584 
       
   585     return image_style_url($style['name'], $file_path) ? $file_path : FALSE;
       
   586   }
       
   587 
       
   588   /**
       
   589    * Count the number of images currently create for a style.
       
   590    */
       
   591   function getImageCount($style) {
       
   592     return count(file_scan_directory('public://styles/' . $style['name'], '/.*/'));
       
   593   }
       
   594 
       
   595   /**
       
   596    * Test creating an image style with a numeric name and ensuring it can be
       
   597    * applied to an image.
       
   598    */
       
   599   function testNumericStyleName() {
       
   600     $style_name = rand();
       
   601     $style_label = $this->randomString();
       
   602     $edit = array(
       
   603       'name' => $style_name,
       
   604       'label' => $style_label,
       
   605     );
       
   606     $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
       
   607     $this->assertRaw(t('Style %name was created.', array('%name' => $style_label)), 'Image style successfully created.');
       
   608     $options = image_style_options();
       
   609     $this->assertTrue(array_key_exists($style_name, $options), format_string('Array key %key exists.', array('%key' => $style_name)));
       
   610   }
       
   611 
       
   612   /**
       
   613    * General test to add a style, add/remove/edit effects to it, then delete it.
       
   614    */
       
   615   function testStyle() {
       
   616     // Setup a style to be created and effects to add to it.
       
   617     $style_name = strtolower($this->randomName(10));
       
   618     $style_label = $this->randomString();
       
   619     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
   620     $effect_edits = array(
       
   621       'image_resize' => array(
       
   622         'data[width]' => 100,
       
   623         'data[height]' => 101,
       
   624       ),
       
   625       'image_scale' => array(
       
   626         'data[width]' => 110,
       
   627         'data[height]' => 111,
       
   628         'data[upscale]' => 1,
       
   629       ),
       
   630       'image_scale_and_crop' => array(
       
   631         'data[width]' => 120,
       
   632         'data[height]' => 121,
       
   633       ),
       
   634       'image_crop' => array(
       
   635         'data[width]' => 130,
       
   636         'data[height]' => 131,
       
   637         'data[anchor]' => 'center-center',
       
   638       ),
       
   639       'image_desaturate' => array(
       
   640         // No options for desaturate.
       
   641       ),
       
   642       'image_rotate' => array(
       
   643         'data[degrees]' => 5,
       
   644         'data[random]' => 1,
       
   645         'data[bgcolor]' => '#FFFF00',
       
   646       ),
       
   647     );
       
   648 
       
   649     // Add style form.
       
   650 
       
   651     $edit = array(
       
   652       'name' => $style_name,
       
   653       'label' => $style_label,
       
   654     );
       
   655     $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
       
   656     $this->assertRaw(t('Style %name was created.', array('%name' => $style_label)), 'Image style successfully created.');
       
   657 
       
   658     // Add effect form.
       
   659 
       
   660     // Add each sample effect to the style.
       
   661     foreach ($effect_edits as $effect => $edit) {
       
   662       // Add the effect.
       
   663       $this->drupalPost($style_path, array('new' => $effect), t('Add'));
       
   664       if (!empty($edit)) {
       
   665         $this->drupalPost(NULL, $edit, t('Add effect'));
       
   666       }
       
   667     }
       
   668 
       
   669     // Edit effect form.
       
   670 
       
   671     // Revisit each form to make sure the effect was saved.
       
   672     drupal_static_reset('image_styles');
       
   673     $style = image_style_load($style_name);
       
   674 
       
   675     foreach ($style['effects'] as $ieid => $effect) {
       
   676       $this->drupalGet($style_path . '/effects/' . $ieid);
       
   677       foreach ($effect_edits[$effect['name']] as $field => $value) {
       
   678         $this->assertFieldByName($field, $value, format_string('The %field field in the %effect effect has the correct value of %value.', array('%field' => $field, '%effect' => $effect['name'], '%value' => $value)));
       
   679       }
       
   680     }
       
   681 
       
   682     // Image style overview form (ordering and renaming).
       
   683 
       
   684     // Confirm the order of effects is maintained according to the order we
       
   685     // added the fields.
       
   686     $effect_edits_order = array_keys($effect_edits);
       
   687     $effects_order = array_values($style['effects']);
       
   688     $order_correct = TRUE;
       
   689     foreach ($effects_order as $index => $effect) {
       
   690       if ($effect_edits_order[$index] != $effect['name']) {
       
   691         $order_correct = FALSE;
       
   692       }
       
   693     }
       
   694     $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
       
   695 
       
   696     // Test the style overview form.
       
   697     // Change the name of the style and adjust the weights of effects.
       
   698     $style_name = strtolower($this->randomName(10));
       
   699     $style_label = $this->randomString();
       
   700     $weight = count($effect_edits);
       
   701     $edit = array(
       
   702       'name' => $style_name,
       
   703       'label' => $style_label,
       
   704     );
       
   705     foreach ($style['effects'] as $ieid => $effect) {
       
   706       $edit['effects[' . $ieid . '][weight]'] = $weight;
       
   707       $weight--;
       
   708     }
       
   709 
       
   710     // Create an image to make sure it gets flushed after saving.
       
   711     $image_path = $this->createSampleImage($style);
       
   712     $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
       
   713 
       
   714     $this->drupalPost($style_path, $edit, t('Update style'));
       
   715 
       
   716     // Note that after changing the style name, the style path is changed.
       
   717     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
   718 
       
   719     // Check that the URL was updated.
       
   720     $this->drupalGet($style_path);
       
   721     $this->assertResponse(200, format_string('Image style %original renamed to %new', array('%original' => $style['label'], '%new' => $style_label)));
       
   722 
       
   723     // Check that the image was flushed after updating the style.
       
   724     // This is especially important when renaming the style. Make sure that
       
   725     // the old image directory has been deleted.
       
   726     $this->assertEqual($this->getImageCount($style), 0, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', array('%style' => $style['label'])));
       
   727 
       
   728     // Load the style by the new name with the new weights.
       
   729     drupal_static_reset('image_styles');
       
   730     $style = image_style_load($style_name, NULL);
       
   731 
       
   732     // Confirm the new style order was saved.
       
   733     $effect_edits_order = array_reverse($effect_edits_order);
       
   734     $effects_order = array_values($style['effects']);
       
   735     $order_correct = TRUE;
       
   736     foreach ($effects_order as $index => $effect) {
       
   737       if ($effect_edits_order[$index] != $effect['name']) {
       
   738         $order_correct = FALSE;
       
   739       }
       
   740     }
       
   741     $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
       
   742 
       
   743     // Image effect deletion form.
       
   744 
       
   745     // Create an image to make sure it gets flushed after deleting an effect.
       
   746     $image_path = $this->createSampleImage($style);
       
   747     $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
       
   748 
       
   749     // Test effect deletion form.
       
   750     $effect = array_pop($style['effects']);
       
   751     $this->drupalPost($style_path . '/effects/' . $effect['ieid'] . '/delete', array(), t('Delete'));
       
   752     $this->assertRaw(t('The image effect %name has been deleted.', array('%name' => $effect['label'])), 'Image effect deleted.');
       
   753 
       
   754     // Style deletion form.
       
   755 
       
   756     // Delete the style.
       
   757     $this->drupalPost('admin/config/media/image-styles/delete/' . $style_name, array(), t('Delete'));
       
   758 
       
   759     // Confirm the style directory has been removed.
       
   760     $directory = file_default_scheme() . '://styles/' . $style_name;
       
   761     $this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', array('%style' => $style['label'])));
       
   762 
       
   763     drupal_static_reset('image_styles');
       
   764     $this->assertFalse(image_style_load($style_name), format_string('Image style %style successfully deleted.', array('%style' => $style['label'])));
       
   765 
       
   766   }
       
   767 
       
   768   /**
       
   769    * Test to override, edit, then revert a style.
       
   770    */
       
   771   function testDefaultStyle() {
       
   772     // Setup a style to be created and effects to add to it.
       
   773     $style_name = 'thumbnail';
       
   774     $style_label = 'Thumbnail (100x100)';
       
   775     $edit_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
   776     $delete_path = 'admin/config/media/image-styles/delete/' . $style_name;
       
   777     $revert_path = 'admin/config/media/image-styles/revert/' . $style_name;
       
   778 
       
   779     // Ensure deleting a default is not possible.
       
   780     $this->drupalGet($delete_path);
       
   781     $this->assertText(t('Page not found'), 'Default styles may not be deleted.');
       
   782 
       
   783     // Ensure that editing a default is not possible (without overriding).
       
   784     $this->drupalGet($edit_path);
       
   785     $disabled_field = $this->xpath('//input[@id=:id and @disabled="disabled"]', array(':id' => 'edit-name'));
       
   786     $this->assertTrue($disabled_field, 'Default styles may not be renamed.');
       
   787     $this->assertNoField('edit-submit', 'Default styles may not be edited.');
       
   788     $this->assertNoField('edit-add', 'Default styles may not have new effects added.');
       
   789 
       
   790     // Create an image to make sure the default works before overriding.
       
   791     drupal_static_reset('image_styles');
       
   792     $style = image_style_load($style_name);
       
   793     $image_path = $this->createSampleImage($style);
       
   794     $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
       
   795 
       
   796     // Verify that effects attached to a default style do not have an ieid key.
       
   797     foreach ($style['effects'] as $effect) {
       
   798       $this->assertFalse(isset($effect['ieid']), format_string('The %effect effect does not have an ieid.', array('%effect' => $effect['name'])));
       
   799     }
       
   800 
       
   801     // Override the default.
       
   802     $this->drupalPost($edit_path, array(), t('Override defaults'));
       
   803     $this->assertRaw(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $style_label)), 'Default image style may be overridden.');
       
   804 
       
   805     // Add sample effect to the overridden style.
       
   806     $this->drupalPost($edit_path, array('new' => 'image_desaturate'), t('Add'));
       
   807     drupal_static_reset('image_styles');
       
   808     $style = image_style_load($style_name);
       
   809 
       
   810     // Verify that effects attached to the style have an ieid now.
       
   811     foreach ($style['effects'] as $effect) {
       
   812       $this->assertTrue(isset($effect['ieid']), format_string('The %effect effect has an ieid.', array('%effect' => $effect['name'])));
       
   813     }
       
   814 
       
   815     // The style should now have 2 effect, the original scale provided by core
       
   816     // and the desaturate effect we added in the override.
       
   817     $effects = array_values($style['effects']);
       
   818     $this->assertEqual($effects[0]['name'], 'image_scale', 'The default effect still exists in the overridden style.');
       
   819     $this->assertEqual($effects[1]['name'], 'image_desaturate', 'The added effect exists in the overridden style.');
       
   820 
       
   821     // Check that we are able to rename an overridden style.
       
   822     $this->drupalGet($edit_path);
       
   823     $disabled_field = $this->xpath('//input[@id=:id and @disabled="disabled"]', array(':id' => 'edit-name'));
       
   824     $this->assertFalse($disabled_field, 'Overridden styles may be renamed.');
       
   825 
       
   826     // Create an image to ensure the override works properly.
       
   827     $image_path = $this->createSampleImage($style);
       
   828     $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
       
   829 
       
   830     // Revert the image style.
       
   831     $this->drupalPost($revert_path, array(), t('Revert'));
       
   832     drupal_static_reset('image_styles');
       
   833     $style = image_style_load($style_name);
       
   834 
       
   835     // The style should now have the single effect for scale.
       
   836     $effects = array_values($style['effects']);
       
   837     $this->assertEqual($effects[0]['name'], 'image_scale', 'The default effect still exists in the reverted style.');
       
   838     $this->assertFalse(array_key_exists(1, $effects), 'The added effect has been removed in the reverted style.');
       
   839   }
       
   840 
       
   841   /**
       
   842    * Test deleting a style and choosing a replacement style.
       
   843    */
       
   844   function testStyleReplacement() {
       
   845     // Create a new style.
       
   846     $style_name = strtolower($this->randomName(10));
       
   847     $style_label = $this->randomString();
       
   848     image_style_save(array('name' => $style_name, 'label' => $style_label));
       
   849     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
   850 
       
   851     // Create an image field that uses the new style.
       
   852     $field_name = strtolower($this->randomName(10));
       
   853     $this->createImageField($field_name, 'article');
       
   854     $instance = field_info_instance('node', $field_name, 'article');
       
   855     $instance['display']['default']['type'] = 'image';
       
   856     $instance['display']['default']['settings']['image_style'] = $style_name;
       
   857     field_update_instance($instance);
       
   858 
       
   859     // Create a new node with an image attached.
       
   860     $test_image = current($this->drupalGetTestFiles('image'));
       
   861     $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
       
   862     $node = node_load($nid);
       
   863 
       
   864     // Test that image is displayed using newly created style.
       
   865     $this->drupalGet('node/' . $nid);
       
   866     $this->assertRaw(check_plain(image_style_url($style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style @style.', array('@style' => $style_name)));
       
   867 
       
   868     // Rename the style and make sure the image field is updated.
       
   869     $new_style_name = strtolower($this->randomName(10));
       
   870     $new_style_label = $this->randomString();
       
   871     $edit = array(
       
   872       'name' => $new_style_name,
       
   873       'label' => $new_style_label,
       
   874     );
       
   875     $this->drupalPost('admin/config/media/image-styles/edit/' . $style_name, $edit, t('Update style'));
       
   876     $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
       
   877     $this->drupalGet('node/' . $nid);
       
   878     $this->assertRaw(check_plain(image_style_url($new_style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style replacement style.'));
       
   879 
       
   880     // Delete the style and choose a replacement style.
       
   881     $edit = array(
       
   882       'replacement' => 'thumbnail',
       
   883     );
       
   884     $this->drupalPost('admin/config/media/image-styles/delete/' . $new_style_name, $edit, t('Delete'));
       
   885     $message = t('Style %name was deleted.', array('%name' => $new_style_label));
       
   886     $this->assertRaw($message, $message);
       
   887 
       
   888     $this->drupalGet('node/' . $nid);
       
   889     $this->assertRaw(check_plain(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style replacement style.'));
       
   890   }
       
   891 }
       
   892 
       
   893 /**
       
   894  * Test class to check that formatters and display settings are working.
       
   895  */
       
   896 class ImageFieldDisplayTestCase extends ImageFieldTestCase {
       
   897   public static function getInfo() {
       
   898     return array(
       
   899       'name' => 'Image field display tests',
       
   900       'description' => 'Test the display of image fields.',
       
   901       'group' => 'Image',
       
   902     );
       
   903   }
       
   904 
       
   905   /**
       
   906    * Test image formatters on node display for public files.
       
   907    */
       
   908   function testImageFieldFormattersPublic() {
       
   909     $this->_testImageFieldFormatters('public');
       
   910   }
       
   911 
       
   912   /**
       
   913    * Test image formatters on node display for private files.
       
   914    */
       
   915   function testImageFieldFormattersPrivate() {
       
   916     // Remove access content permission from anonymous users.
       
   917     user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access content' => FALSE));
       
   918     $this->_testImageFieldFormatters('private');
       
   919   }
       
   920 
       
   921   /**
       
   922    * Test image formatters on node display.
       
   923    */
       
   924   function _testImageFieldFormatters($scheme) {
       
   925     $field_name = strtolower($this->randomName());
       
   926     $this->createImageField($field_name, 'article', array('uri_scheme' => $scheme));
       
   927     // Create a new node with an image attached.
       
   928     $test_image = current($this->drupalGetTestFiles('image'));
       
   929     $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
       
   930     $node = node_load($nid, NULL, TRUE);
       
   931 
       
   932     // Test that the default formatter is being used.
       
   933     $image_uri = $node->{$field_name}[LANGUAGE_NONE][0]['uri'];
       
   934     $image_info = array(
       
   935       'path' => $image_uri,
       
   936       'width' => 40,
       
   937       'height' => 20,
       
   938     );
       
   939     $default_output = theme('image', $image_info);
       
   940     $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
       
   941 
       
   942     // Test the image linked to file formatter.
       
   943     $instance = field_info_instance('node', $field_name, 'article');
       
   944     $instance['display']['default']['type'] = 'image';
       
   945     $instance['display']['default']['settings']['image_link'] = 'file';
       
   946     field_update_instance($instance);
       
   947     $default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE));
       
   948     $this->drupalGet('node/' . $nid);
       
   949     $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
       
   950     // Verify that the image can be downloaded.
       
   951     $this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
       
   952     if ($scheme == 'private') {
       
   953       // Only verify HTTP headers when using private scheme and the headers are
       
   954       // sent by Drupal.
       
   955       $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
       
   956       $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'private', 'Cache-Control header was sent.');
       
   957 
       
   958       // Log out and try to access the file.
       
   959       $this->drupalLogout();
       
   960       $this->drupalGet(file_create_url($image_uri));
       
   961       $this->assertResponse('403', 'Access denied to original image as anonymous user.');
       
   962 
       
   963       // Log in again.
       
   964       $this->drupalLogin($this->admin_user);
       
   965     }
       
   966 
       
   967     // Test the image linked to content formatter.
       
   968     $instance['display']['default']['settings']['image_link'] = 'content';
       
   969     field_update_instance($instance);
       
   970     $default_output = l(theme('image', $image_info), 'node/' . $nid, array('html' => TRUE, 'attributes' => array('class' => 'active')));
       
   971     $this->drupalGet('node/' . $nid);
       
   972     $this->assertRaw($default_output, 'Image linked to content formatter displaying correctly on full node view.');
       
   973 
       
   974     // Test the image style 'thumbnail' formatter.
       
   975     $instance['display']['default']['settings']['image_link'] = '';
       
   976     $instance['display']['default']['settings']['image_style'] = 'thumbnail';
       
   977     field_update_instance($instance);
       
   978     // Ensure the derivative image is generated so we do not have to deal with
       
   979     // image style callback paths.
       
   980     $this->drupalGet(image_style_url('thumbnail', $image_uri));
       
   981     // Need to create the URL again since it will change if clean URLs
       
   982     // are disabled.
       
   983     $image_info['path'] = image_style_url('thumbnail', $image_uri);
       
   984     $image_info['width'] = 100;
       
   985     $image_info['height'] = 50;
       
   986     $default_output = theme('image', $image_info);
       
   987     $this->drupalGet('node/' . $nid);
       
   988     $this->assertRaw($default_output, 'Image style thumbnail formatter displaying correctly on full node view.');
       
   989 
       
   990     if ($scheme == 'private') {
       
   991       // Log out and try to access the file.
       
   992       $this->drupalLogout();
       
   993       $this->drupalGet(image_style_url('thumbnail', $image_uri));
       
   994       $this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
       
   995     }
       
   996   }
       
   997 
       
   998   /**
       
   999    * Tests for image field settings.
       
  1000    */
       
  1001   function testImageFieldSettings() {
       
  1002     $test_image = current($this->drupalGetTestFiles('image'));
       
  1003     list(, $test_image_extension) = explode('.', $test_image->filename);
       
  1004     $field_name = strtolower($this->randomName());
       
  1005     $instance_settings = array(
       
  1006       'alt_field' => 1,
       
  1007       'file_extensions' => $test_image_extension,
       
  1008       'max_filesize' => '50 KB',
       
  1009       'max_resolution' => '100x100',
       
  1010       'min_resolution' => '10x10',
       
  1011       'title_field' => 1,
       
  1012     );
       
  1013     $widget_settings = array(
       
  1014       'preview_image_style' => 'medium',
       
  1015     );
       
  1016     $field = $this->createImageField($field_name, 'article', array(), $instance_settings, $widget_settings);
       
  1017     $field['deleted'] = 0;
       
  1018     $table = _field_sql_storage_tablename($field);
       
  1019     $schema = drupal_get_schema($table, TRUE);
       
  1020     $instance = field_info_instance('node', $field_name, 'article');
       
  1021 
       
  1022     $this->drupalGet('node/add/article');
       
  1023     $this->assertText(t('Files must be less than 50 KB.'), 'Image widget max file size is displayed on article form.');
       
  1024     $this->assertText(t('Allowed file types: ' . $test_image_extension . '.'), 'Image widget allowed file types displayed on article form.');
       
  1025     $this->assertText(t('Images must be between 10x10 and 100x100 pixels.'), 'Image widget allowed resolution displayed on article form.');
       
  1026 
       
  1027     // We have to create the article first and then edit it because the alt
       
  1028     // and title fields do not display until the image has been attached.
       
  1029     $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
       
  1030     $this->drupalGet('node/' . $nid . '/edit');
       
  1031     $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][alt]', '', 'Alt field displayed on article form.');
       
  1032     $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][title]', '', 'Title field displayed on article form.');
       
  1033     // Verify that the attached image is being previewed using the 'medium'
       
  1034     // style.
       
  1035     $node = node_load($nid, NULL, TRUE);
       
  1036     $image_info = array(
       
  1037       'path' => image_style_url('medium', $node->{$field_name}[LANGUAGE_NONE][0]['uri']),
       
  1038       'width' => 220,
       
  1039       'height' => 110,
       
  1040     );
       
  1041     $default_output = theme('image', $image_info);
       
  1042     $this->assertRaw($default_output, "Preview image is displayed using 'medium' style.");
       
  1043 
       
  1044     // Add alt/title fields to the image and verify that they are displayed.
       
  1045     $image_info = array(
       
  1046       'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
       
  1047       'alt' => $this->randomName(),
       
  1048       'title' => $this->randomName(),
       
  1049       'width' => 40,
       
  1050       'height' => 20,
       
  1051     );
       
  1052     $edit = array(
       
  1053       $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $image_info['alt'],
       
  1054       $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $image_info['title'],
       
  1055     );
       
  1056     $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
       
  1057     $default_output = theme('image', $image_info);
       
  1058     $this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.');
       
  1059 
       
  1060     // Verify that alt/title longer than allowed results in a validation error.
       
  1061     $test_size = 2000;
       
  1062     $edit = array(
       
  1063       $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $this->randomName($test_size),
       
  1064       $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $this->randomName($test_size),
       
  1065     );
       
  1066     $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
       
  1067     $this->assertRaw(t('Alternate text cannot be longer than %max characters but is currently %length characters long.', array(
       
  1068       '%max' => $schema['fields'][$field_name .'_alt']['length'],
       
  1069       '%length' => $test_size,
       
  1070     )));
       
  1071     $this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array(
       
  1072       '%max' => $schema['fields'][$field_name .'_title']['length'],
       
  1073       '%length' => $test_size,
       
  1074     )));
       
  1075   }
       
  1076 
       
  1077   /**
       
  1078    * Test passing attributes into the image field formatters.
       
  1079    */
       
  1080   function testImageFieldFormatterAttributes() {
       
  1081     $image = theme('image_formatter', array(
       
  1082       'item' => array(
       
  1083         'uri' => 'http://example.com/example.png',
       
  1084         'attributes' => array(
       
  1085           'data-image-field-formatter' => 'testFound',
       
  1086         ),
       
  1087         'alt' => t('Image field formatter attribute test.'),
       
  1088         'title' => t('Image field formatter'),
       
  1089       ),
       
  1090     ));
       
  1091     $this->assertTrue(stripos($image, 'testFound') > 0, 'Image field formatters can have attributes.');
       
  1092   }
       
  1093 
       
  1094   /**
       
  1095    * Test use of a default image with an image field.
       
  1096    */
       
  1097   function testImageFieldDefaultImage() {
       
  1098     // Create a new image field.
       
  1099     $field_name = strtolower($this->randomName());
       
  1100     $this->createImageField($field_name, 'article');
       
  1101 
       
  1102     // Create a new node, with no images and verify that no images are
       
  1103     // displayed.
       
  1104     $node = $this->drupalCreateNode(array('type' => 'article'));
       
  1105     $this->drupalGet('node/' . $node->nid);
       
  1106     // Verify that no image is displayed on the page by checking for the class
       
  1107     // that would be used on the image field.
       
  1108     $this->assertNoPattern('<div class="(.*?)field-name-' . strtr($field_name, '_', '-') . '(.*?)">', 'No image displayed when no image is attached and no default image specified.');
       
  1109 
       
  1110     // Add a default image to the public imagefield instance.
       
  1111     $images = $this->drupalGetTestFiles('image');
       
  1112     $edit = array(
       
  1113       'files[field_settings_default_image]' => drupal_realpath($images[0]->uri),
       
  1114     );
       
  1115     $this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
       
  1116     // Clear field info cache so the new default image is detected.
       
  1117     field_info_cache_clear();
       
  1118     $field = field_info_field($field_name);
       
  1119     $image = file_load($field['settings']['default_image']);
       
  1120     $this->assertTrue($image->status == FILE_STATUS_PERMANENT, 'The default image status is permanent.');
       
  1121     $default_output = theme('image', array('path' => $image->uri));
       
  1122     $this->drupalGet('node/' . $node->nid);
       
  1123     $this->assertRaw($default_output, 'Default image displayed when no user supplied image is present.');
       
  1124 
       
  1125     // Create a node with an image attached and ensure that the default image
       
  1126     // is not displayed.
       
  1127     $nid = $this->uploadNodeImage($images[1], $field_name, 'article');
       
  1128     $node = node_load($nid, NULL, TRUE);
       
  1129     $image_info = array(
       
  1130       'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
       
  1131       'width' => 40,
       
  1132       'height' => 20,
       
  1133     );
       
  1134     $image_output = theme('image', $image_info);
       
  1135     $this->drupalGet('node/' . $nid);
       
  1136     $this->assertNoRaw($default_output, 'Default image is not displayed when user supplied image is present.');
       
  1137     $this->assertRaw($image_output, 'User supplied image is displayed.');
       
  1138 
       
  1139     // Remove default image from the field and make sure it is no longer used.
       
  1140     $edit = array(
       
  1141       'field[settings][default_image][fid]' => 0,
       
  1142     );
       
  1143     $this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
       
  1144     // Clear field info cache so the new default image is detected.
       
  1145     field_info_cache_clear();
       
  1146     $field = field_info_field($field_name);
       
  1147     $this->assertFalse($field['settings']['default_image'], 'Default image removed from field.');
       
  1148     // Create an image field that uses the private:// scheme and test that the
       
  1149     // default image works as expected.
       
  1150     $private_field_name = strtolower($this->randomName());
       
  1151     $this->createImageField($private_field_name, 'article', array('uri_scheme' => 'private'));
       
  1152     // Add a default image to the new field.
       
  1153     $edit = array(
       
  1154       'files[field_settings_default_image]' => drupal_realpath($images[1]->uri),
       
  1155     );
       
  1156     $this->drupalPost('admin/structure/types/manage/article/fields/' . $private_field_name, $edit, t('Save settings'));
       
  1157     $private_field = field_info_field($private_field_name);
       
  1158     $image = file_load($private_field['settings']['default_image']);
       
  1159     $this->assertEqual('private', file_uri_scheme($image->uri), 'Default image uses private:// scheme.');
       
  1160     $this->assertTrue($image->status == FILE_STATUS_PERMANENT, 'The default image status is permanent.');
       
  1161     // Create a new node with no image attached and ensure that default private
       
  1162     // image is displayed.
       
  1163     $node = $this->drupalCreateNode(array('type' => 'article'));
       
  1164     $default_output = theme('image', array('path' => $image->uri));
       
  1165     $this->drupalGet('node/' . $node->nid);
       
  1166     $this->assertRaw($default_output, 'Default private image displayed when no user supplied image is present.');
       
  1167   }
       
  1168 }
       
  1169 
       
  1170 /**
       
  1171  * Test class to check for various validations.
       
  1172  */
       
  1173 class ImageFieldValidateTestCase extends ImageFieldTestCase {
       
  1174   public static function getInfo() {
       
  1175     return array(
       
  1176       'name' => 'Image field validation tests',
       
  1177       'description' => 'Tests validation functions such as min/max resolution.',
       
  1178       'group' => 'Image',
       
  1179     );
       
  1180   }
       
  1181 
       
  1182   /**
       
  1183    * Test min/max resolution settings.
       
  1184    */
       
  1185   function testResolution() {
       
  1186     $field_name = strtolower($this->randomName());
       
  1187     $min_resolution = 50;
       
  1188     $max_resolution = 100;
       
  1189     $instance_settings = array(
       
  1190       'max_resolution' => $max_resolution . 'x' . $max_resolution,
       
  1191       'min_resolution' => $min_resolution . 'x' . $min_resolution,
       
  1192     );
       
  1193     $this->createImageField($field_name, 'article', array(), $instance_settings);
       
  1194 
       
  1195     // We want a test image that is too small, and a test image that is too
       
  1196     // big, so cycle through test image files until we have what we need.
       
  1197     $image_that_is_too_big = FALSE;
       
  1198     $image_that_is_too_small = FALSE;
       
  1199     foreach ($this->drupalGetTestFiles('image') as $image) {
       
  1200       $info = image_get_info($image->uri);
       
  1201       if ($info['width'] > $max_resolution) {
       
  1202         $image_that_is_too_big = $image;
       
  1203       }
       
  1204       if ($info['width'] < $min_resolution) {
       
  1205         $image_that_is_too_small = $image;
       
  1206       }
       
  1207       if ($image_that_is_too_small && $image_that_is_too_big) {
       
  1208         break;
       
  1209       }
       
  1210     }
       
  1211     $nid = $this->uploadNodeImage($image_that_is_too_small, $field_name, 'article');
       
  1212     $this->assertText(t('The specified file ' . $image_that_is_too_small->filename . ' could not be uploaded. The image is too small; the minimum dimensions are 50x50 pixels.'), 'Node save failed when minimum image resolution was not met.');
       
  1213     $nid = $this->uploadNodeImage($image_that_is_too_big, $field_name, 'article');
       
  1214     $this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'), 'Image exceeding max resolution was properly resized.');
       
  1215   }
       
  1216 }
       
  1217 
       
  1218 /**
       
  1219  * Tests that images have correct dimensions when styled.
       
  1220  */
       
  1221 class ImageDimensionsTestCase extends DrupalWebTestCase {
       
  1222 
       
  1223   public static function getInfo() {
       
  1224     return array(
       
  1225       'name' => 'Image dimensions',
       
  1226       'description' => 'Tests that images have correct dimensions when styled.',
       
  1227       'group' => 'Image',
       
  1228     );
       
  1229   }
       
  1230 
       
  1231   function setUp() {
       
  1232     parent::setUp('image_module_test');
       
  1233   }
       
  1234 
       
  1235   /**
       
  1236    * Test styled image dimensions cumulatively.
       
  1237    */
       
  1238   function testImageDimensions() {
       
  1239     // Create a working copy of the file.
       
  1240     $files = $this->drupalGetTestFiles('image');
       
  1241     $file = reset($files);
       
  1242     $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
       
  1243 
       
  1244     // Create a style.
       
  1245     $style = image_style_save(array('name' => 'test', 'label' => 'Test'));
       
  1246     $generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
       
  1247     $url = image_style_url('test', $original_uri);
       
  1248 
       
  1249     $variables = array(
       
  1250       'style_name' => 'test',
       
  1251       'path' => $original_uri,
       
  1252       'width' => 40,
       
  1253       'height' => 20,
       
  1254     );
       
  1255 
       
  1256     // Scale an image that is wider than it is high.
       
  1257     $effect = array(
       
  1258       'name' => 'image_scale',
       
  1259       'data' => array(
       
  1260         'width' => 120,
       
  1261         'height' => 90,
       
  1262         'upscale' => TRUE,
       
  1263       ),
       
  1264       'isid' => $style['isid'],
       
  1265     );
       
  1266 
       
  1267     image_effect_save($effect);
       
  1268     $img_tag = theme_image_style($variables);
       
  1269     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="120" height="60" alt="" />', 'Expected img tag was found.');
       
  1270     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1271     $this->drupalGet($url);
       
  1272     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1273     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1274     $image_info = image_get_info($generated_uri);
       
  1275     $this->assertEqual($image_info['width'], 120, 'Expected width was found.');
       
  1276     $this->assertEqual($image_info['height'], 60, 'Expected height was found.');
       
  1277 
       
  1278     // Rotate 90 degrees anticlockwise.
       
  1279     $effect = array(
       
  1280       'name' => 'image_rotate',
       
  1281       'data' => array(
       
  1282         'degrees' => -90,
       
  1283         'random' => FALSE,
       
  1284       ),
       
  1285       'isid' => $style['isid'],
       
  1286     );
       
  1287 
       
  1288     image_effect_save($effect);
       
  1289     $img_tag = theme_image_style($variables);
       
  1290     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="60" height="120" alt="" />', 'Expected img tag was found.');
       
  1291     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1292     $this->drupalGet($url);
       
  1293     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1294     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1295     $image_info = image_get_info($generated_uri);
       
  1296     $this->assertEqual($image_info['width'], 60, 'Expected width was found.');
       
  1297     $this->assertEqual($image_info['height'], 120, 'Expected height was found.');
       
  1298 
       
  1299     // Scale an image that is higher than it is wide (rotated by previous effect).
       
  1300     $effect = array(
       
  1301       'name' => 'image_scale',
       
  1302       'data' => array(
       
  1303         'width' => 120,
       
  1304         'height' => 90,
       
  1305         'upscale' => TRUE,
       
  1306       ),
       
  1307       'isid' => $style['isid'],
       
  1308     );
       
  1309 
       
  1310     image_effect_save($effect);
       
  1311     $img_tag = theme_image_style($variables);
       
  1312     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
       
  1313     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1314     $this->drupalGet($url);
       
  1315     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1316     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1317     $image_info = image_get_info($generated_uri);
       
  1318     $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
       
  1319     $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
       
  1320 
       
  1321     // Test upscale disabled.
       
  1322     $effect = array(
       
  1323       'name' => 'image_scale',
       
  1324       'data' => array(
       
  1325         'width' => 400,
       
  1326         'height' => 200,
       
  1327         'upscale' => FALSE,
       
  1328       ),
       
  1329       'isid' => $style['isid'],
       
  1330     );
       
  1331 
       
  1332     image_effect_save($effect);
       
  1333     $img_tag = theme_image_style($variables);
       
  1334     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
       
  1335     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1336     $this->drupalGet($url);
       
  1337     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1338     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1339     $image_info = image_get_info($generated_uri);
       
  1340     $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
       
  1341     $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
       
  1342 
       
  1343     // Add a desaturate effect.
       
  1344     $effect = array(
       
  1345       'name' => 'image_desaturate',
       
  1346       'data' => array(),
       
  1347       'isid' => $style['isid'],
       
  1348     );
       
  1349 
       
  1350     image_effect_save($effect);
       
  1351     $img_tag = theme_image_style($variables);
       
  1352     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
       
  1353     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1354     $this->drupalGet($url);
       
  1355     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1356     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1357     $image_info = image_get_info($generated_uri);
       
  1358     $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
       
  1359     $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
       
  1360 
       
  1361     // Add a random rotate effect.
       
  1362     $effect = array(
       
  1363       'name' => 'image_rotate',
       
  1364       'data' => array(
       
  1365         'degrees' => 180,
       
  1366         'random' => TRUE,
       
  1367       ),
       
  1368       'isid' => $style['isid'],
       
  1369     );
       
  1370 
       
  1371     image_effect_save($effect);
       
  1372     $img_tag = theme_image_style($variables);
       
  1373     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
       
  1374     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1375     $this->drupalGet($url);
       
  1376     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1377     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1378 
       
  1379 
       
  1380     // Add a crop effect.
       
  1381     $effect = array(
       
  1382       'name' => 'image_crop',
       
  1383       'data' => array(
       
  1384         'width' => 30,
       
  1385         'height' => 30,
       
  1386         'anchor' => 'center-center',
       
  1387       ),
       
  1388       'isid' => $style['isid'],
       
  1389     );
       
  1390 
       
  1391     image_effect_save($effect);
       
  1392     $img_tag = theme_image_style($variables);
       
  1393     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="30" height="30" alt="" />', 'Expected img tag was found.');
       
  1394     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1395     $this->drupalGet($url);
       
  1396     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1397     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1398     $image_info = image_get_info($generated_uri);
       
  1399     $this->assertEqual($image_info['width'], 30, 'Expected width was found.');
       
  1400     $this->assertEqual($image_info['height'], 30, 'Expected height was found.');
       
  1401 
       
  1402     // Rotate to a non-multiple of 90 degrees.
       
  1403     $effect = array(
       
  1404       'name' => 'image_rotate',
       
  1405       'data' => array(
       
  1406         'degrees' => 57,
       
  1407         'random' => FALSE,
       
  1408       ),
       
  1409       'isid' => $style['isid'],
       
  1410     );
       
  1411 
       
  1412     $effect = image_effect_save($effect);
       
  1413     $img_tag = theme_image_style($variables);
       
  1414     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
       
  1415     $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
       
  1416     $this->drupalGet($url);
       
  1417     $this->assertResponse(200, 'Image was generated at the URL.');
       
  1418     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
       
  1419 
       
  1420     image_effect_delete($effect);
       
  1421 
       
  1422     // Ensure that an effect with no dimensions callback unsets the dimensions.
       
  1423     // This ensures compatibility with 7.0 contrib modules.
       
  1424     $effect = array(
       
  1425       'name' => 'image_module_test_null',
       
  1426       'data' => array(),
       
  1427       'isid' => $style['isid'],
       
  1428     );
       
  1429 
       
  1430     image_effect_save($effect);
       
  1431     $img_tag = theme_image_style($variables);
       
  1432     $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
       
  1433   }
       
  1434 }
       
  1435 
       
  1436 /**
       
  1437  * Tests image_dimensions_scale().
       
  1438  */
       
  1439 class ImageDimensionsScaleTestCase extends DrupalUnitTestCase {
       
  1440   public static function getInfo() {
       
  1441     return array(
       
  1442       'name' => 'image_dimensions_scale()',
       
  1443       'description' => 'Tests all control flow branches in image_dimensions_scale().',
       
  1444       'group' => 'Image',
       
  1445     );
       
  1446   }
       
  1447 
       
  1448   /**
       
  1449    * Tests all control flow branches in image_dimensions_scale().
       
  1450    */
       
  1451   function testImageDimensionsScale() {
       
  1452     // Define input / output datasets to test different branch conditions.
       
  1453     $test = array();
       
  1454 
       
  1455     // Test branch conditions:
       
  1456     // - No height.
       
  1457     // - Upscale, don't need to upscale.
       
  1458     $tests[] = array(
       
  1459       'input' => array(
       
  1460         'dimensions' => array(
       
  1461           'width' => 1000,
       
  1462           'height' => 2000,
       
  1463         ),
       
  1464         'width' => 200,
       
  1465         'height' => NULL,
       
  1466         'upscale' => TRUE,
       
  1467       ),
       
  1468       'output' => array(
       
  1469         'dimensions' => array(
       
  1470           'width' => 200,
       
  1471           'height' => 400,
       
  1472         ),
       
  1473         'return_value' => TRUE,
       
  1474       ),
       
  1475     );
       
  1476 
       
  1477     // Test branch conditions:
       
  1478     // - No width.
       
  1479     // - Don't upscale, don't need to upscale.
       
  1480     $tests[] = array(
       
  1481       'input' => array(
       
  1482         'dimensions' => array(
       
  1483           'width' => 1000,
       
  1484           'height' => 800,
       
  1485         ),
       
  1486         'width' => NULL,
       
  1487         'height' => 140,
       
  1488         'upscale' => FALSE,
       
  1489       ),
       
  1490       'output' => array(
       
  1491         'dimensions' => array(
       
  1492           'width' => 175,
       
  1493           'height' => 140,
       
  1494         ),
       
  1495         'return_value' => TRUE,
       
  1496       ),
       
  1497     );
       
  1498 
       
  1499     // Test branch conditions:
       
  1500     // - Source aspect ratio greater than target.
       
  1501     // - Upscale, need to upscale.
       
  1502     $tests[] = array(
       
  1503       'input' => array(
       
  1504         'dimensions' => array(
       
  1505           'width' => 8,
       
  1506           'height' => 20,
       
  1507         ),
       
  1508         'width' => 200,
       
  1509         'height' => 140,
       
  1510         'upscale' => TRUE,
       
  1511       ),
       
  1512       'output' => array(
       
  1513         'dimensions' => array(
       
  1514           'width' => 56,
       
  1515           'height' => 140,
       
  1516         ),
       
  1517         'return_value' => TRUE,
       
  1518       ),
       
  1519     );
       
  1520 
       
  1521     // Test branch condition: target aspect ratio greater than source.
       
  1522     $tests[] = array(
       
  1523       'input' => array(
       
  1524         'dimensions' => array(
       
  1525           'width' => 2000,
       
  1526           'height' => 800,
       
  1527         ),
       
  1528         'width' => 200,
       
  1529         'height' => 140,
       
  1530         'upscale' => FALSE,
       
  1531       ),
       
  1532       'output' => array(
       
  1533         'dimensions' => array(
       
  1534           'width' => 200,
       
  1535           'height' => 80,
       
  1536         ),
       
  1537         'return_value' => TRUE,
       
  1538       ),
       
  1539     );
       
  1540 
       
  1541     // Test branch condition: don't upscale, need to upscale.
       
  1542     $tests[] = array(
       
  1543       'input' => array(
       
  1544         'dimensions' => array(
       
  1545           'width' => 100,
       
  1546           'height' => 50,
       
  1547         ),
       
  1548         'width' => 200,
       
  1549         'height' => 140,
       
  1550         'upscale' => FALSE,
       
  1551       ),
       
  1552       'output' => array(
       
  1553         'dimensions' => array(
       
  1554           'width' => 100,
       
  1555           'height' => 50,
       
  1556         ),
       
  1557         'return_value' => FALSE,
       
  1558       ),
       
  1559     );
       
  1560 
       
  1561     foreach ($tests as $test) {
       
  1562       // Process the test dataset.
       
  1563       $return_value = image_dimensions_scale($test['input']['dimensions'], $test['input']['width'], $test['input']['height'], $test['input']['upscale']);
       
  1564 
       
  1565       // Check the width.
       
  1566       $this->assertEqual($test['output']['dimensions']['width'], $test['input']['dimensions']['width'], format_string('Computed width (@computed_width) equals expected width (@expected_width)', array('@computed_width' => $test['output']['dimensions']['width'], '@expected_width' => $test['input']['dimensions']['width'])));
       
  1567 
       
  1568       // Check the height.
       
  1569       $this->assertEqual($test['output']['dimensions']['height'], $test['input']['dimensions']['height'], format_string('Computed height (@computed_height) equals expected height (@expected_height)', array('@computed_height' => $test['output']['dimensions']['height'], '@expected_height' => $test['input']['dimensions']['height'])));
       
  1570 
       
  1571       // Check the return value.
       
  1572       $this->assertEqual($test['output']['return_value'], $return_value, 'Correct return value.');
       
  1573     }
       
  1574   }
       
  1575 }
       
  1576 
       
  1577 /**
       
  1578  * Tests default image settings.
       
  1579  */
       
  1580 class ImageFieldDefaultImagesTestCase extends ImageFieldTestCase {
       
  1581 
       
  1582   public static function getInfo() {
       
  1583     return array(
       
  1584       'name' => 'Image field default images tests',
       
  1585       'description' => 'Tests setting up default images both to the field and field instance.',
       
  1586       'group' => 'Image',
       
  1587     );
       
  1588   }
       
  1589 
       
  1590   function setUp() {
       
  1591     parent::setUp(array('field_ui'));
       
  1592   }
       
  1593 
       
  1594   /**
       
  1595    * Tests CRUD for fields and fields instances with default images.
       
  1596    */
       
  1597   function testDefaultImages() {
       
  1598     // Create files to use as the default images.
       
  1599     $files = $this->drupalGetTestFiles('image');
       
  1600     $default_images = array();
       
  1601     foreach (array('field', 'instance', 'instance2', 'field_new', 'instance_new') as $image_target) {
       
  1602       $file = array_pop($files);
       
  1603       $file = file_save($file);
       
  1604       $default_images[$image_target] = $file;
       
  1605     }
       
  1606 
       
  1607     // Create an image field and add an instance to the article content type.
       
  1608     $field_name = strtolower($this->randomName());
       
  1609     $field_settings = array(
       
  1610       'default_image' => $default_images['field']->fid,
       
  1611     );
       
  1612     $instance_settings = array(
       
  1613       'default_image' => $default_images['instance']->fid,
       
  1614     );
       
  1615     $widget_settings = array(
       
  1616       'preview_image_style' => 'medium',
       
  1617     );
       
  1618     $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings);
       
  1619     $field = field_info_field($field_name);
       
  1620     $instance = field_info_instance('node', $field_name, 'article');
       
  1621 
       
  1622     // Add another instance with another default image to the page content type.
       
  1623     $instance2 = array_merge($instance, array(
       
  1624       'bundle' => 'page',
       
  1625       'settings' => array(
       
  1626         'default_image' => $default_images['instance2']->fid,
       
  1627       ),
       
  1628     ));
       
  1629     field_create_instance($instance2);
       
  1630     $instance2 = field_info_instance('node', $field_name, 'page');
       
  1631 
       
  1632 
       
  1633     // Confirm the defaults are present on the article field admin form.
       
  1634     $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
       
  1635     $this->assertFieldByXpath(
       
  1636       '//input[@name="field[settings][default_image][fid]"]',
       
  1637       $default_images['field']->fid,
       
  1638       format_string(
       
  1639         'Article image field default equals expected file ID of @fid.',
       
  1640         array('@fid' => $default_images['field']->fid)
       
  1641       )
       
  1642     );
       
  1643     $this->assertFieldByXpath(
       
  1644       '//input[@name="instance[settings][default_image][fid]"]',
       
  1645       $default_images['instance']->fid,
       
  1646       format_string(
       
  1647         'Article image field instance default equals expected file ID of @fid.',
       
  1648         array('@fid' => $default_images['instance']->fid)
       
  1649       )
       
  1650     );
       
  1651 
       
  1652     // Confirm the defaults are present on the page field admin form.
       
  1653     $this->drupalGet("admin/structure/types/manage/page/fields/$field_name");
       
  1654     $this->assertFieldByXpath(
       
  1655       '//input[@name="field[settings][default_image][fid]"]',
       
  1656       $default_images['field']->fid,
       
  1657       format_string(
       
  1658         'Page image field default equals expected file ID of @fid.',
       
  1659         array('@fid' => $default_images['field']->fid)
       
  1660       )
       
  1661     );
       
  1662     $this->assertFieldByXpath(
       
  1663       '//input[@name="instance[settings][default_image][fid]"]',
       
  1664       $default_images['instance2']->fid,
       
  1665       format_string(
       
  1666         'Page image field instance default equals expected file ID of @fid.',
       
  1667         array('@fid' => $default_images['instance2']->fid)
       
  1668       )
       
  1669     );
       
  1670 
       
  1671     // Confirm that the image default is shown for a new article node.
       
  1672     $article = $this->drupalCreateNode(array('type' => 'article'));
       
  1673     $article_built = node_view($article);
       
  1674     $this->assertEqual(
       
  1675       $article_built[$field_name]['#items'][0]['fid'],
       
  1676       $default_images['instance']->fid,
       
  1677       format_string(
       
  1678         'A new article node without an image has the expected default image file ID of @fid.',
       
  1679         array('@fid' => $default_images['instance']->fid)
       
  1680       )
       
  1681     );
       
  1682 
       
  1683     // Confirm that the image default is shown for a new page node.
       
  1684     $page = $this->drupalCreateNode(array('type' => 'page'));
       
  1685     $page_built = node_view($page);
       
  1686     $this->assertEqual(
       
  1687       $page_built[$field_name]['#items'][0]['fid'],
       
  1688       $default_images['instance2']->fid,
       
  1689       format_string(
       
  1690         'A new page node without an image has the expected default image file ID of @fid.',
       
  1691         array('@fid' => $default_images['instance2']->fid)
       
  1692       )
       
  1693     );
       
  1694 
       
  1695     // Upload a new default for the field.
       
  1696     $field['settings']['default_image'] = $default_images['field_new']->fid;
       
  1697     field_update_field($field);
       
  1698 
       
  1699     // Confirm that the new field default is used on the article admin form.
       
  1700     $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
       
  1701     $this->assertFieldByXpath(
       
  1702       '//input[@name="field[settings][default_image][fid]"]',
       
  1703       $default_images['field_new']->fid,
       
  1704       format_string(
       
  1705         'Updated image field default equals expected file ID of @fid.',
       
  1706         array('@fid' => $default_images['field_new']->fid)
       
  1707       )
       
  1708     );
       
  1709 
       
  1710     // Reload the nodes and confirm the field instance defaults are used.
       
  1711     $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
       
  1712     $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
       
  1713     $this->assertEqual(
       
  1714       $article_built[$field_name]['#items'][0]['fid'],
       
  1715       $default_images['instance']->fid,
       
  1716       format_string(
       
  1717         'An existing article node without an image has the expected default image file ID of @fid.',
       
  1718         array('@fid' => $default_images['instance']->fid)
       
  1719       )
       
  1720     );
       
  1721     $this->assertEqual(
       
  1722       $page_built[$field_name]['#items'][0]['fid'],
       
  1723       $default_images['instance2']->fid,
       
  1724       format_string(
       
  1725         'An existing page node without an image has the expected default image file ID of @fid.',
       
  1726         array('@fid' => $default_images['instance2']->fid)
       
  1727       )
       
  1728     );
       
  1729 
       
  1730     // Upload a new default for the article's field instance.
       
  1731     $instance['settings']['default_image'] = $default_images['instance_new']->fid;
       
  1732     field_update_instance($instance);
       
  1733 
       
  1734     // Confirm the new field instance default is used on the article field
       
  1735     // admin form.
       
  1736     $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
       
  1737     $this->assertFieldByXpath(
       
  1738       '//input[@name="instance[settings][default_image][fid]"]',
       
  1739       $default_images['instance_new']->fid,
       
  1740       format_string(
       
  1741         'Updated article image field instance default equals expected file ID of @fid.',
       
  1742         array('@fid' => $default_images['instance_new']->fid)
       
  1743       )
       
  1744     );
       
  1745 
       
  1746     // Reload the nodes.
       
  1747     $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
       
  1748     $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
       
  1749 
       
  1750     // Confirm the article uses the new default.
       
  1751     $this->assertEqual(
       
  1752       $article_built[$field_name]['#items'][0]['fid'],
       
  1753       $default_images['instance_new']->fid,
       
  1754       format_string(
       
  1755         'An existing article node without an image has the expected default image file ID of @fid.',
       
  1756         array('@fid' => $default_images['instance_new']->fid)
       
  1757       )
       
  1758     );
       
  1759     // Confirm the page remains unchanged.
       
  1760     $this->assertEqual(
       
  1761       $page_built[$field_name]['#items'][0]['fid'],
       
  1762       $default_images['instance2']->fid,
       
  1763       format_string(
       
  1764         'An existing page node without an image has the expected default image file ID of @fid.',
       
  1765         array('@fid' => $default_images['instance2']->fid)
       
  1766       )
       
  1767     );
       
  1768 
       
  1769     // Remove the instance default from articles.
       
  1770     $instance['settings']['default_image'] = NULL;
       
  1771     field_update_instance($instance);
       
  1772 
       
  1773     // Confirm the article field instance default has been removed.
       
  1774     $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
       
  1775     $this->assertFieldByXpath(
       
  1776       '//input[@name="instance[settings][default_image][fid]"]',
       
  1777       '',
       
  1778       'Updated article image field instance default has been successfully removed.'
       
  1779     );
       
  1780 
       
  1781     // Reload the nodes.
       
  1782     $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
       
  1783     $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
       
  1784     // Confirm the article uses the new field (not instance) default.
       
  1785     $this->assertEqual(
       
  1786       $article_built[$field_name]['#items'][0]['fid'],
       
  1787       $default_images['field_new']->fid,
       
  1788       format_string(
       
  1789         'An existing article node without an image has the expected default image file ID of @fid.',
       
  1790         array('@fid' => $default_images['field_new']->fid)
       
  1791       )
       
  1792     );
       
  1793     // Confirm the page remains unchanged.
       
  1794     $this->assertEqual(
       
  1795       $page_built[$field_name]['#items'][0]['fid'],
       
  1796       $default_images['instance2']->fid,
       
  1797       format_string(
       
  1798         'An existing page node without an image has the expected default image file ID of @fid.',
       
  1799         array('@fid' => $default_images['instance2']->fid)
       
  1800       )
       
  1801     );
       
  1802   }
       
  1803 
       
  1804 }
       
  1805 
       
  1806 /**
       
  1807  * Tests image theme functions.
       
  1808  */
       
  1809 class ImageThemeFunctionWebTestCase extends DrupalWebTestCase {
       
  1810 
       
  1811   public static function getInfo() {
       
  1812     return array(
       
  1813       'name' => 'Image theme functions',
       
  1814       'description' => 'Test that the image theme functions work correctly.',
       
  1815       'group' => 'Image',
       
  1816     );
       
  1817   }
       
  1818 
       
  1819   function setUp() {
       
  1820     parent::setUp(array('image'));
       
  1821   }
       
  1822 
       
  1823   /**
       
  1824    * Tests usage of the image field formatters.
       
  1825    */
       
  1826   function testImageFormatterTheme() {
       
  1827     // Create an image.
       
  1828     $files = $this->drupalGetTestFiles('image');
       
  1829     $file = reset($files);
       
  1830     $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
       
  1831 
       
  1832     // Create a style.
       
  1833     image_style_save(array('name' => 'test', 'label' => 'Test'));
       
  1834     $url = image_style_url('test', $original_uri);
       
  1835 
       
  1836     // Test using theme_image_formatter() without an image title, alt text, or
       
  1837     // link options.
       
  1838     $path = $this->randomName();
       
  1839     $element = array(
       
  1840       '#theme' => 'image_formatter',
       
  1841       '#image_style' => 'test',
       
  1842       '#item' => array(
       
  1843         'uri' => $original_uri,
       
  1844       ),
       
  1845       '#path' => array(
       
  1846         'path' => $path,
       
  1847       ),
       
  1848     );
       
  1849     $rendered_element = render($element);
       
  1850     $expected_result = '<a href="' . url($path) . '"><img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" /></a>';
       
  1851     $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders without title, alt, or path options.');
       
  1852 
       
  1853     // Link the image to a fragment on the page, and not a full URL.
       
  1854     $fragment = $this->randomName();
       
  1855     $element['#path']['path'] = '';
       
  1856     $element['#path']['options'] = array(
       
  1857       'external' => TRUE,
       
  1858       'fragment' => $fragment,
       
  1859     );
       
  1860     $rendered_element = render($element);
       
  1861     $expected_result = '<a href="#' . $fragment . '"><img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" /></a>';
       
  1862     $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders a link fragment.');
       
  1863   }
       
  1864 
       
  1865 }
       
  1866 
       
  1867 /**
       
  1868  * Tests flushing of image styles.
       
  1869  */
       
  1870 class ImageStyleFlushTest extends ImageFieldTestCase {
       
  1871 
       
  1872   public static function getInfo() {
       
  1873     return array(
       
  1874       'name' => 'Image style flushing',
       
  1875       'description' => 'Tests flushing of image styles.',
       
  1876       'group' => 'Image',
       
  1877     );
       
  1878   }
       
  1879 
       
  1880   /**
       
  1881    * Given an image style and a wrapper, generate an image.
       
  1882    */
       
  1883   function createSampleImage($style, $wrapper) {
       
  1884     static $file;
       
  1885 
       
  1886     if (!isset($file)) {
       
  1887       $files = $this->drupalGetTestFiles('image');
       
  1888       $file = reset($files);
       
  1889     }
       
  1890 
       
  1891     // Make sure we have an image in our wrapper testing file directory.
       
  1892     $source_uri = file_unmanaged_copy($file->uri, $wrapper . '://');
       
  1893     // Build the derivative image.
       
  1894     $derivative_uri = image_style_path($style['name'], $source_uri);
       
  1895     $derivative = image_style_create_derivative($style, $source_uri, $derivative_uri);
       
  1896 
       
  1897     return $derivative ? $derivative_uri : FALSE;
       
  1898   }
       
  1899 
       
  1900   /**
       
  1901    * Count the number of images currently created for a style in a wrapper.
       
  1902    */
       
  1903   function getImageCount($style, $wrapper) {
       
  1904     return count(file_scan_directory($wrapper . '://styles/' . $style['name'], '/.*/'));
       
  1905   }
       
  1906 
       
  1907   /**
       
  1908    * General test to flush a style.
       
  1909    */
       
  1910   function testFlush() {
       
  1911 
       
  1912     // Setup a style to be created and effects to add to it.
       
  1913     $style_name = strtolower($this->randomName(10));
       
  1914     $style_label = $this->randomString();
       
  1915     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
       
  1916     $effect_edits = array(
       
  1917       'image_resize' => array(
       
  1918         'data[width]' => 100,
       
  1919         'data[height]' => 101,
       
  1920       ),
       
  1921       'image_scale' => array(
       
  1922         'data[width]' => 110,
       
  1923         'data[height]' => 111,
       
  1924         'data[upscale]' => 1,
       
  1925       ),
       
  1926     );
       
  1927 
       
  1928     // Add style form.
       
  1929     $edit = array(
       
  1930       'name' => $style_name,
       
  1931       'label' => $style_label,
       
  1932     );
       
  1933     $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
       
  1934     // Add each sample effect to the style.
       
  1935     foreach ($effect_edits as $effect => $edit) {
       
  1936       // Add the effect.
       
  1937       $this->drupalPost($style_path, array('new' => $effect), t('Add'));
       
  1938       if (!empty($edit)) {
       
  1939         $this->drupalPost(NULL, $edit, t('Add effect'));
       
  1940       }
       
  1941     }
       
  1942 
       
  1943     // Load the saved image style.
       
  1944     $style = image_style_load($style_name);
       
  1945 
       
  1946     // Create an image for the 'public' wrapper.
       
  1947     $image_path = $this->createSampleImage($style, 'public');
       
  1948     // Expecting to find 2 images, one is the sample.png image shown in
       
  1949     // image style preview.
       
  1950     $this->assertEqual($this->getImageCount($style, 'public'), 2, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
       
  1951 
       
  1952     // Create an image for the 'private' wrapper.
       
  1953     $image_path = $this->createSampleImage($style, 'private');
       
  1954     $this->assertEqual($this->getImageCount($style, 'private'), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
       
  1955 
       
  1956     // Remove the 'image_scale' effect and updates the style, which in turn
       
  1957     // forces an image style flush.
       
  1958     $effect = array_pop($style['effects']);
       
  1959     $this->drupalPost($style_path . '/effects/' . $effect['ieid'] . '/delete', array(), t('Delete'));
       
  1960     $this->assertResponse(200);
       
  1961     $this->drupalPost($style_path, array(), t('Update style'));
       
  1962     $this->assertResponse(200);
       
  1963 
       
  1964     // Post flush, expected 1 image in the 'public' wrapper (sample.png).
       
  1965     $this->assertEqual($this->getImageCount($style, 'public'), 1, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style['name'], '%wrapper' => 'public')));
       
  1966 
       
  1967     // Post flush, expected no image in the 'private' wrapper.
       
  1968     $this->assertEqual($this->getImageCount($style, 'private'), 0, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style['name'], '%wrapper' => 'private')));
       
  1969   }
       
  1970 }