Newer
Older
<?php
/**
* @file
Dries Buytaert
committed
* Tests for image.module.
*/
/**
* TODO: Test the following functions.
*
* image.effects.inc:
* image_style_generate()
* image_style_create_derivative()
*
* image.module:
* image_style_load()
* image_style_save()
* image_style_delete()
* image_style_options()
* image_style_flush()
* image_effect_definition_load()
* image_effect_load()
* image_effect_save()
* image_effect_delete()
* image_filter_keyword()
*/
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* This class provides methods specifically for testing Image's field handling.
*/
class ImageFieldTestCase extends DrupalWebTestCase {
protected $admin_user;
function setUp() {
parent::setUp('image');
$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'));
$this->drupalLogin($this->admin_user);
}
/**
* Create a new image field.
*
* @param $name
* The name of the new field (all lowercase), exclude the "field_" prefix.
* @param $type_name
* The node type that this field will be added to.
* @param $field_settings
* A list of field settings that will be added to the defaults.
* @param $instance_settings
* A list of instance settings that will be added to the instance defaults.
* @param $widget_settings
* A list of widget settings that will be added to the widget defaults.
*/
function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
$field = array(
'field_name' => $name,
'type' => 'image',
'settings' => array(),
'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
);
$field['settings'] = array_merge($field['settings'], $field_settings);
field_create_field($field);
$instance = array(
'field_name' => $field['field_name'],
'entity_type' => 'node',
'label' => $name,
'bundle' => $type_name,
'required' => !empty($instance_settings['required']),
'settings' => array(),
'widget' => array(
'type' => 'image_image',
'settings' => array(),
),
);
$instance['settings'] = array_merge($instance['settings'], $instance_settings);
$instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings);
return field_create_instance($instance);
}
/**
* Upload an image to a node.
*
* @param $image
* A file object representing the image to upload.
* @param $field_name
* Name of the image field the image should be attached to.
* @param $type
* The type of node to create.
*/
function uploadNodeImage($image, $field_name, $type) {
$edit = array(
'title' => $this->randomName(),
);
Angie Byron
committed
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri);
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
// Retrieve ID of the newly created node from the current URL.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
return isset($matches[1]) ? $matches[1] : FALSE;
}
}
/**
* Tests the functions for generating paths and URLs for image styles.
*/
class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
protected $style_name;
protected $image_info;
protected $image_filepath;
public static function getInfo() {
return array(
'name' => 'Image styles path and URL functions',
'description' => 'Tests functions for generating paths and URLs to image styles.',
'group' => 'Image',
);
}
function setUp() {
Dries Buytaert
committed
parent::setUp('image_module_test');
$this->style_name = 'style_foo';
image_style_save(array('name' => $this->style_name));
}
/**
* Test image_style_path().
*/
function testImageStylePath() {
Dries Buytaert
committed
$scheme = 'public';
$actual = image_style_path($this->style_name, "$scheme://foo/bar.gif");
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, t('Got the path for a file URI.'));
Dries Buytaert
committed
$actual = image_style_path($this->style_name, 'foo/bar.gif');
Dries Buytaert
committed
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, t('Got the path for a relative file path.'));
Dries Buytaert
committed
}
/**
* Test image_style_url() with a file using the "public://" scheme.
*/
function testImageStyleUrlAndPathPublic() {
$this->_testImageStyleUrlAndPath('public');
}
/**
* Test image_style_url() with a file using the "private://" scheme.
*/
function testImageStyleUrlAndPathPrivate() {
$this->_testImageStyleUrlAndPath('private');
}
Dries Buytaert
committed
/**
* Test image_style_url() with the "public://" scheme and unclean URLs.
*/
function testImageStylUrlAndPathPublicUnclean() {
$this->_testImageStyleUrlAndPath('public', FALSE);
}
/**
* Test image_style_url() with the "private://" schema and unclean URLs.
*/
function testImageStyleUrlAndPathPrivateUnclean() {
$this->_testImageStyleUrlAndPath('private', FALSE);
}
/**
* Test image_style_url().
*/
Dries Buytaert
committed
function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE) {
Dries Buytaert
committed
// Make the default scheme neither "public" nor "private" to verify the
Angie Byron
committed
// functions work for other than the default scheme.
Dries Buytaert
committed
variable_set('file_default_scheme', 'temporary');
Dries Buytaert
committed
variable_set('clean_url', $clean_url);
Dries Buytaert
committed
// Create the directories for the styles.
Dries Buytaert
committed
$directory = $scheme . '://styles/' . $this->style_name;
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$this->assertNotIdentical(FALSE, $status, t('Created the directory for the generated images for the test style.'));
Dries Buytaert
committed
// Create a working copy of the file.
$files = $this->drupalGetTestFiles('image');
Angie Byron
committed
$file = array_shift($files);
Dries Buytaert
committed
$image_info = image_get_info($file->uri);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
Dries Buytaert
committed
// Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download().
variable_set('image_module_test_file_download', $original_uri);
$this->assertNotIdentical(FALSE, $original_uri, t('Created the generated image file.'));
Dries Buytaert
committed
Dries Buytaert
committed
// Get the URL of a file that has not been generated and try to create it.
$generated_uri = image_style_path($this->style_name, $original_uri);
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
Dries Buytaert
committed
$generate_url = image_style_url($this->style_name, $original_uri);
Dries Buytaert
committed
if (!$clean_url) {
$this->assertTrue(strpos($generate_url, '?q=') !== FALSE, 'When using non-clean URLS, the system path contains the query string.');
}
// Add some extra chars to the token.
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
$this->assertResponse(403, 'Image was inaccessible at the URL wih an invalid token.');
// Change the parameter name so the token is missing.
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
$this->assertResponse(403, 'Image was inaccessible at the URL wih a missing token.');
Dries Buytaert
committed
// Fetch the URL that generates the file.
Dries Buytaert
committed
$this->drupalGet($generate_url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$this->assertRaw(file_get_contents($generated_uri), t('URL returns expected file.'));
Dries Buytaert
committed
$generated_image_info = image_get_info($generated_uri);
$this->assertEqual($this->drupalGetHeader('Content-Type'), $generated_image_info['mime_type'], t('Expected Content-Type was reported.'));
$this->assertEqual($this->drupalGetHeader('Content-Length'), $generated_image_info['file_size'], t('Expected Content-Length was reported.'));
Dries Buytaert
committed
if ($scheme == 'private') {
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', t('Expires header was sent.'));
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', t('Cache-Control header was set to prevent caching.'));
Dries Buytaert
committed
$this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', t('Expected custom header has been added.'));
Angie Byron
committed
// Make sure that a second request to the already existing derivate works
// too.
Angie Byron
committed
$this->assertResponse(200, t('Image was generated at the URL.'));
// Repeat this with a different file that we do not have access to and
// make sure that access is denied.
$file_noaccess = array_shift($files);
$original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME);
$generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
$this->assertFalse(file_exists($generated_uri_noaccess), t('Generated file does not exist.'));
$generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess);
$this->drupalGet($generate_url_noaccess);
$this->assertResponse(403, t('Confirmed that access is denied for the private image style.') );
// Verify that images are not appended to the response. Currently this test only uses PNG images.
if (strpos($generate_url, '.png') === FALSE ) {
Angie Byron
committed
$this->fail('Confirming that private image styles are not appended require PNG file.');
}
else {
// Check for PNG-Signature (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2) in the
// response body.
Angie Byron
committed
$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.');
Dries Buytaert
committed
}
elseif ($clean_url) {
// Add some extra chars to the token.
$this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
$this->assertResponse(200, 'Existing image was accessible at the URL wih an invalid token.');
}
}
}
/**
* Use the image_test.module's mock toolkit to ensure that the effects are
* properly passing parameters to the image toolkit.
*/
class ImageEffectsUnitTest extends ImageToolkitTestCase {
public static function getInfo() {
return array(
'name' => 'Image effects',
'description' => 'Test that the image effects pass parameters to the toolkit correctly.',
'group' => 'Image',
);
}
function setUp() {
David Rothstein
committed
parent::setUp('image_module_test');
module_load_include('inc', 'image', 'image.effects');
}
/**
* Test the image_resize_effect() function.
*/
function testResizeEffect() {
$this->assertTrue(image_resize_effect($this->image, array('width' => 1, 'height' => 2)), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('resize'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual($calls['resize'][0][1], 1, t('Width was passed correctly'));
$this->assertEqual($calls['resize'][0][2], 2, t('Height was passed correctly'));
}
/**
* Test the image_scale_effect() function.
*/
function testScaleEffect() {
// @todo: need to test upscaling.
$this->assertTrue(image_scale_effect($this->image, array('width' => 10, 'height' => 10)), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('resize'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual($calls['resize'][0][1], 10, t('Width was passed correctly'));
$this->assertEqual($calls['resize'][0][2], 5, t('Height was based off aspect ratio and passed correctly'));
}
/**
* Test the image_crop_effect() function.
*/
function testCropEffect() {
// @todo should test the keyword offsets.
$this->assertTrue(image_crop_effect($this->image, array('anchor' => 'top-1', 'width' => 3, 'height' => 4)), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('crop'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual($calls['crop'][0][1], 0, t('X was passed correctly'));
$this->assertEqual($calls['crop'][0][2], 1, t('Y was passed correctly'));
$this->assertEqual($calls['crop'][0][3], 3, t('Width was passed correctly'));
$this->assertEqual($calls['crop'][0][4], 4, t('Height was passed correctly'));
}
/**
* Test the image_scale_and_crop_effect() function.
*/
function testScaleAndCropEffect() {
$this->assertTrue(image_scale_and_crop_effect($this->image, array('width' => 5, 'height' => 10)), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('resize', 'crop'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual($calls['crop'][0][1], 7.5, t('X was computed and passed correctly'));
$this->assertEqual($calls['crop'][0][2], 0, t('Y was computed and passed correctly'));
$this->assertEqual($calls['crop'][0][3], 5, t('Width was computed and passed correctly'));
$this->assertEqual($calls['crop'][0][4], 10, t('Height was computed and passed correctly'));
}
/**
* Test the image_desaturate_effect() function.
*/
function testDesaturateEffect() {
$this->assertTrue(image_desaturate_effect($this->image, array()), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('desaturate'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual(count($calls['desaturate'][0]), 1, t('Only the image was passed.'));
}
/**
* Test the image_rotate_effect() function.
*/
function testRotateEffect() {
// @todo: need to test with 'random' => TRUE
$this->assertTrue(image_rotate_effect($this->image, array('degrees' => 90, 'bgcolor' => '#fff')), t('Function returned the expected value.'));
$this->assertToolkitOperationsCalled(array('rotate'));
// Check the parameters.
$calls = image_test_get_all_calls();
$this->assertEqual($calls['rotate'][0][1], 90, t('Degrees were passed correctly'));
$this->assertEqual($calls['rotate'][0][2], 0xffffff, t('Background color was passed correctly'));
}
David Rothstein
committed
/**
* Test image effect caching.
*/
function testImageEffectsCaching() {
$image_effect_definitions_called = &drupal_static('image_module_test_image_effect_info_alter');
// First call should grab a fresh copy of the data.
$effects = image_effect_definitions();
$this->assertTrue($image_effect_definitions_called === 1, 'image_effect_definitions() generated data.');
// Second call should come from cache.
drupal_static_reset('image_effect_definitions');
drupal_static_reset('image_module_test_image_effect_info_alter');
$cached_effects = image_effect_definitions();
$this->assertTrue(is_null($image_effect_definitions_called), 'image_effect_definitions() returned data from cache.');
$this->assertTrue($effects == $cached_effects, 'Cached effects are the same as generated effects.');
}
}
/**
* Tests creation, deletion, and editing of image styles and effects.
*/
class ImageAdminStylesUnitTest extends ImageFieldTestCase {
Dries Buytaert
committed
public static function getInfo() {
return array(
'name' => 'Image styles and effects UI configuration',
'description' => 'Tests creation, deletion, and editing of image styles and effects at the UI level.',
'group' => 'Image',
);
}
/**
* Given an image style, generate an image.
*/
function createSampleImage($style) {
static $file_path;
// First, we need to make sure we have an image in our testing
// file directory. Copy over an image on the first run.
if (!isset($file_path)) {
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
$file_path = file_unmanaged_copy($file->uri);
}
return image_style_url($style['name'], $file_path) ? $file_path : FALSE;
}
/**
* Count the number of images currently create for a style.
*/
function getImageCount($style) {
return count(file_scan_directory('public://styles/' . $style['name'], '/.*/'));
}
Angie Byron
committed
/**
* Test creating an image style with a numeric name and ensuring it can be
* applied to an image.
*/
function testNumericStyleName() {
$style_name = rand();
$edit = array(
'name' => $style_name,
);
$this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
$this->assertRaw(t('Style %name was created.', array('%name' => $style_name)), t('Image style successfully created.'));
$options = image_style_options();
$this->assertTrue(array_key_exists($style_name, $options), t('Array key %key exists.', array('%key' => $style_name)));
}
/**
* General test to add a style, add/remove/edit effects to it, then delete it.
*/
function testStyle() {
// Setup a style to be created and effects to add to it.
$style_name = strtolower($this->randomName(10));
Dries Buytaert
committed
$style_path = 'admin/config/media/image-styles/edit/' . $style_name;
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
$effect_edits = array(
'image_resize' => array(
'data[width]' => 100,
'data[height]' => 101,
),
'image_scale' => array(
'data[width]' => 110,
'data[height]' => 111,
'data[upscale]' => 1,
),
'image_scale_and_crop' => array(
'data[width]' => 120,
'data[height]' => 121,
),
'image_crop' => array(
'data[width]' => 130,
'data[height]' => 131,
'data[anchor]' => 'center-center',
),
'image_desaturate' => array(
// No options for desaturate.
),
'image_rotate' => array(
'data[degrees]' => 5,
'data[random]' => 1,
'data[bgcolor]' => '#FFFF00',
),
);
// Add style form.
$edit = array(
'name' => $style_name,
);
Dries Buytaert
committed
$this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
$this->assertRaw(t('Style %name was created.', array('%name' => $style_name)), t('Image style successfully created.'));
// Add effect form.
// Add each sample effect to the style.
foreach ($effect_edits as $effect => $edit) {
// Add the effect.
$this->drupalPost($style_path, array('new' => $effect), t('Add'));
if (!empty($edit)) {
$this->drupalPost(NULL, $edit, t('Add effect'));
}
}
// Edit effect form.
// Revisit each form to make sure the effect was saved.
Angie Byron
committed
drupal_static_reset('image_styles');
$style = image_style_load($style_name);
foreach ($style['effects'] as $ieid => $effect) {
$this->drupalGet($style_path . '/effects/' . $ieid);
foreach ($effect_edits[$effect['name']] as $field => $value) {
$this->assertFieldByName($field, $value, t('The %field field in the %effect effect has the correct value of %value.', array('%field' => $field, '%effect' => $effect['name'], '%value' => $value)));
}
}
// Image style overview form (ordering and renaming).
// Confirm the order of effects is maintained according to the order we
// added the fields.
$effect_edits_order = array_keys($effect_edits);
$effects_order = array_values($style['effects']);
$order_correct = TRUE;
foreach ($effects_order as $index => $effect) {
if ($effect_edits_order[$index] != $effect['name']) {
$order_correct = FALSE;
}
}
$this->assertTrue($order_correct, t('The order of the effects is correctly set by default.'));
// Test the style overview form.
// Change the name of the style and adjust the weights of effects.
$style_name = strtolower($this->randomName(10));
$weight = count($effect_edits);
$edit = array(
'name' => $style_name,
);
foreach ($style['effects'] as $ieid => $effect) {
$edit['effects[' . $ieid . '][weight]'] = $weight;
$weight--;
}
// Create an image to make sure it gets flushed after saving.
$image_path = $this->createSampleImage($style);
$this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
$this->drupalPost($style_path, $edit, t('Update style'));
// Note that after changing the style name, the style path is changed.
Dries Buytaert
committed
$style_path = 'admin/config/media/image-styles/edit/' . $style_name;
// Check that the URL was updated.
$this->drupalGet($style_path);
$this->assertResponse(200, t('Image style %original renamed to %new', array('%original' => $style['name'], '%new' => $style_name)));
// Check that the image was flushed after updating the style.
// This is especially important when renaming the style. Make sure that
// the old image directory has been deleted.
$this->assertEqual($this->getImageCount($style), 0, t('Image style %style was flushed after renaming the style and updating the order of effects.', array('%style' => $style['name'])));
// Load the style by the new name with the new weights.
drupal_static_reset('image_styles');
$style = image_style_load($style_name, NULL);
// Confirm the new style order was saved.
$effect_edits_order = array_reverse($effect_edits_order);
$effects_order = array_values($style['effects']);
$order_correct = TRUE;
foreach ($effects_order as $index => $effect) {
if ($effect_edits_order[$index] != $effect['name']) {
$order_correct = FALSE;
}
}
$this->assertTrue($order_correct, t('The order of the effects is correctly set by default.'));
// Image effect deletion form.
// Create an image to make sure it gets flushed after deleting an effect.
$image_path = $this->createSampleImage($style);
$this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
// Test effect deletion form.
$effect = array_pop($style['effects']);
$this->drupalPost($style_path . '/effects/' . $effect['ieid'] . '/delete', array(), t('Delete'));
$this->assertRaw(t('The image effect %name has been deleted.', array('%name' => $effect['label'])), t('Image effect deleted.'));
// Style deletion form.
// Delete the style.
Dries Buytaert
committed
$this->drupalPost('admin/config/media/image-styles/delete/' . $style_name, array(), t('Delete'));
// Confirm the style directory has been removed.
$directory = file_default_scheme() . '://styles/' . $style_name;
$this->assertFalse(is_dir($directory), t('Image style %style directory removed on style deletion.', array('%style' => $style['name'])));
drupal_static_reset('image_styles');
$this->assertFalse(image_style_load($style_name), t('Image style %style successfully deleted.', array('%style' => $style['name'])));
}
Angie Byron
committed
/**
* Test to override, edit, then revert a style.
*/
function testDefaultStyle() {
// Setup a style to be created and effects to add to it.
$style_name = 'thumbnail';
$edit_path = 'admin/config/media/image-styles/edit/' . $style_name;
$delete_path = 'admin/config/media/image-styles/delete/' . $style_name;
$revert_path = 'admin/config/media/image-styles/revert/' . $style_name;
// Ensure deleting a default is not possible.
$this->drupalGet($delete_path);
$this->assertText(t('Page not found'), t('Default styles may not be deleted.'));
Angie Byron
committed
// Ensure that editing a default is not possible (without overriding).
$this->drupalGet($edit_path);
$this->assertNoField('edit-name', t('Default styles may not be renamed.'));
$this->assertNoField('edit-submit', t('Default styles may not be edited.'));
$this->assertNoField('edit-add', t('Default styles may not have new effects added.'));
Angie Byron
committed
// Create an image to make sure the default works before overriding.
drupal_static_reset('image_styles');
$style = image_style_load($style_name);
$image_path = $this->createSampleImage($style);
$this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
Angie Byron
committed
Angie Byron
committed
// Verify that effects attached to a default style do not have an ieid key.
foreach ($style['effects'] as $effect) {
$this->assertFalse(isset($effect['ieid']), t('The %effect effect does not have an ieid.', array('%effect' => $effect['name'])));
Angie Byron
committed
}
Angie Byron
committed
// Override the default.
$this->drupalPost($edit_path, array(), t('Override defaults'));
$this->assertRaw(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $style_name)), t('Default image style may be overridden.'));
Angie Byron
committed
// Add sample effect to the overridden style.
$this->drupalPost($edit_path, array('new' => 'image_desaturate'), t('Add'));
drupal_static_reset('image_styles');
$style = image_style_load($style_name);
Angie Byron
committed
// Verify that effects attached to the style have an ieid now.
foreach ($style['effects'] as $effect) {
$this->assertTrue(isset($effect['ieid']), t('The %effect effect has an ieid.', array('%effect' => $effect['name'])));
Angie Byron
committed
}
Angie Byron
committed
// The style should now have 2 effect, the original scale provided by core
// and the desaturate effect we added in the override.
$effects = array_values($style['effects']);
$this->assertEqual($effects[0]['name'], 'image_scale', t('The default effect still exists in the overridden style.'));
$this->assertEqual($effects[1]['name'], 'image_desaturate', t('The added effect exists in the overridden style.'));
Angie Byron
committed
// Check that we are unable to rename an overridden style.
$this->drupalGet($edit_path);
$this->assertNoField('edit-name', t('Overridden styles may not be renamed.'));
Angie Byron
committed
// Create an image to ensure the override works properly.
$image_path = $this->createSampleImage($style);
$this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
Angie Byron
committed
// Revert the image style.
$this->drupalPost($revert_path, array(), t('Revert'));
drupal_static_reset('image_styles');
$style = image_style_load($style_name);
// The style should now have the single effect for scale.
$effects = array_values($style['effects']);
$this->assertEqual($effects[0]['name'], 'image_scale', t('The default effect still exists in the reverted style.'));
$this->assertFalse(array_key_exists(1, $effects), t('The added effect has been removed in the reverted style.'));
Angie Byron
committed
}
* Test deleting a style and choosing a replacement style.
function testStyleReplacement() {
// Create a new style.
$style_name = strtolower($this->randomName(10));
image_style_save(array('name' => $style_name));
$style_path = 'admin/config/media/image-styles/edit/' . $style_name;
// Create an image field that uses the new style.
$field_name = strtolower($this->randomName(10));
Angie Byron
committed
$this->createImageField($field_name, 'article');
$instance = field_info_instance('node', $field_name, 'article');
Dries Buytaert
committed
$instance['display']['default']['type'] = 'image';
$instance['display']['default']['settings']['image_style'] = $style_name;
field_update_instance($instance);
// Create a new node with an image attached.
$test_image = current($this->drupalGetTestFiles('image'));
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
$node = node_load($nid);
// Test that image is displayed using newly created style.
$this->drupalGet('node/' . $nid);
$this->assertRaw(check_plain(image_style_url($style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), t('Image displayed using style @style.', array('@style' => $style_name)));
// Rename the style and make sure the image field is updated.
$new_style_name = strtolower($this->randomName(10));
$edit = array(
'name' => $new_style_name,
$this->drupalPost('admin/config/media/image-styles/edit/' . $style_name, $edit, t('Update style'));
$this->assertText(t('Changes to the style have been saved.'), t('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
$this->drupalGet('node/' . $nid);
$this->assertRaw(check_plain(image_style_url($new_style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), t('Image displayed using style replacement style.'));
// Delete the style and choose a replacement style.
$edit = array(
'replacement' => 'thumbnail',
$this->drupalPost('admin/config/media/image-styles/delete/' . $new_style_name, $edit, t('Delete'));
$message = t('Style %name was deleted.', array('%name' => $new_style_name));
$this->assertRaw($message, $message);
$this->drupalGet('node/' . $nid);
$this->assertRaw(check_plain(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), t('Image displayed using style replacement style.'));
}
}
/**
* Test class to check that formatters and display settings are working.
*/
class ImageFieldDisplayTestCase extends ImageFieldTestCase {
public static function getInfo() {
return array(
'name' => 'Image field display tests',
'description' => 'Test the display of image fields.',
'group' => 'Image',
);
}
/**
* Test image formatters on node display for public files.
*/
function testImageFieldFormattersPublic() {
$this->_testImageFieldFormatters('public');
}
/**
* Test image formatters on node display for private files.
*/
function testImageFieldFormattersPrivate() {
// Remove access content permission from anonymous users.
user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access content' => FALSE));
$this->_testImageFieldFormatters('private');
}
/**
* Test image formatters on node display.
*/
function _testImageFieldFormatters($scheme) {
Dries Buytaert
committed
$field_name = strtolower($this->randomName());
$this->createImageField($field_name, 'article', array('uri_scheme' => $scheme));
// Create a new node with an image attached.
$test_image = current($this->drupalGetTestFiles('image'));
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
$node = node_load($nid, NULL, TRUE);
// Test that the default formatter is being used.
$image_uri = $node->{$field_name}[LANGUAGE_NONE][0]['uri'];
$image_info = array(
'path' => $image_uri,
'width' => 40,
'height' => 20,
);
$default_output = theme('image', $image_info);
$this->assertRaw($default_output, t('Default formatter displaying correctly on full node view.'));
// Test the image linked to file formatter.
$instance = field_info_instance('node', $field_name, 'article');
Dries Buytaert
committed
$instance['display']['default']['type'] = 'image';
$instance['display']['default']['settings']['image_link'] = 'file';
field_update_instance($instance);
$default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE));
$this->drupalGet('node/' . $nid);
$this->assertRaw($default_output, t('Image linked to file formatter displaying correctly on full node view.'));
// Verify that the image can be downloaded.
$this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), t('File was downloaded successfully.'));
if ($scheme == 'private') {
// Only verify HTTP headers when using private scheme and the headers are
// sent by Drupal.
David Rothstein
committed
$this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', t('Content-Type header was sent.'));
$this->assertEqual($this->drupalGetHeader('Content-Disposition'), 'inline; filename="' . $test_image->filename . '"', t('Content-Disposition header was sent.'));
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'private', t('Cache-Control header was sent.'));
// Log out and try to access the file.
$this->drupalLogout();
$this->drupalGet(file_create_url($image_uri));
$this->assertResponse('403', t('Access denied to original image as anonymous user.'));
// Log in again.
$this->drupalLogin($this->admin_user);
}
// Test the image linked to content formatter.
Dries Buytaert
committed
$instance['display']['default']['settings']['image_link'] = 'content';
field_update_instance($instance);
$default_output = l(theme('image', $image_info), 'node/' . $nid, array('html' => TRUE, 'attributes' => array('class' => 'active')));
$this->drupalGet('node/' . $nid);
$this->assertRaw($default_output, t('Image linked to content formatter displaying correctly on full node view.'));
// Test the image style 'thumbnail' formatter.
Dries Buytaert
committed
$instance['display']['default']['settings']['image_link'] = '';
$instance['display']['default']['settings']['image_style'] = 'thumbnail';
field_update_instance($instance);
// Ensure the derivative image is generated so we do not have to deal with
// image style callback paths.
$this->drupalGet(image_style_url('thumbnail', $image_uri));
// Need to create the URL again since it will change if clean URLs
// are disabled.
$image_info['path'] = image_style_url('thumbnail', $image_uri);
$image_info['width'] = 100;
$image_info['height'] = 50;
$default_output = theme('image', $image_info);
$this->drupalGet('node/' . $nid);
$this->assertRaw($default_output, t('Image style thumbnail formatter displaying correctly on full node view.'));
if ($scheme == 'private') {
// Log out and try to access the file.
$this->drupalLogout();
$this->drupalGet(image_style_url('thumbnail', $image_uri));
$this->assertResponse('403', t('Access denied to image style thumbnail as anonymous user.'));
}
Angie Byron
committed
/**
* Tests for image field settings.
*/
function testImageFieldSettings() {
Angie Byron
committed
$test_image = current($this->drupalGetTestFiles('image'));
list(, $test_image_extension) = explode('.', $test_image->filename);
Dries Buytaert
committed
$field_name = strtolower($this->randomName());
$instance_settings = array(
'alt_field' => 1,
Angie Byron
committed
'file_extensions' => $test_image_extension,
'max_filesize' => '50 KB',
'max_resolution' => '100x100',
'min_resolution' => '10x10',
'title_field' => 1,
);
$widget_settings = array(
'preview_image_style' => 'medium',
);
$field = $this->createImageField($field_name, 'article', array(), $instance_settings, $widget_settings);
$field['deleted'] = 0;
$table = _field_sql_storage_tablename($field);
$schema = drupal_get_schema($table, TRUE);
$instance = field_info_instance('node', $field_name, 'article');
$this->drupalGet('node/add/article');
$this->assertText(t('Files must be less than 50 KB.'), t('Image widget max file size is displayed on article form.'));
$this->assertText(t('Allowed file types: ' . $test_image_extension . '.'), t('Image widget allowed file types displayed on article form.'));
$this->assertText(t('Images must be between 10x10 and 100x100 pixels.'), t('Image widget allowed resolution displayed on article form.'));
// We have to create the article first and then edit it because the alt
// and title fields do not display until the image has been attached.
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
$this->drupalGet('node/' . $nid . '/edit');
$this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][alt]', '', t('Alt field displayed on article form.'));
$this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][title]', '', t('Title field displayed on article form.'));
// Verify that the attached image is being previewed using the 'medium'
// style.
$node = node_load($nid, NULL, TRUE);
$image_info = array(
'path' => image_style_url('medium', $node->{$field_name}[LANGUAGE_NONE][0]['uri']),
'width' => 220,
'height' => 110,
);
$default_output = theme('image', $image_info);
$this->assertRaw($default_output, t("Preview image is displayed using 'medium' style."));
// Add alt/title fields to the image and verify that they are displayed.
$image_info = array(
'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
'alt' => $this->randomName(),
'title' => $this->randomName(),
'width' => 40,
'height' => 20,
);
$edit = array(
$field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $image_info['alt'],
$field_name . '[' . LANGUAGE_NONE . '][0][title]' => $image_info['title'],
);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$default_output = theme('image', $image_info);
$this->assertRaw($default_output, t('Image displayed using user supplied alt and title attributes.'));
// Verify that alt/title longer than allowed results in a validation error.
$test_size = 2000;
$edit = array(
$field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $this->randomName($test_size),
$field_name . '[' . LANGUAGE_NONE . '][0][title]' => $this->randomName($test_size),
);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Alternate text cannot be longer than %max characters but is currently %length characters long.', array(
'%max' => $schema['fields'][$field_name .'_alt']['length'],
'%length' => $test_size,
)));
$this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array(
'%max' => $schema['fields'][$field_name .'_title']['length'],
'%length' => $test_size,
)));
Angie Byron
committed
/**
* Test passing attributes into the image field formatters.
*/
function testImageFieldFormatterAttributes() {
$image = theme('image_formatter', array(
'item' => array(
'uri' => 'http://example.com/example.png',
'attributes' => array(
'data-image-field-formatter' => 'testFound',
),
'alt' => t('Image field formatter attribute test.'),
'title' => t('Image field formatter'),
),
));
$this->assertTrue(stripos($image, 'testFound') > 0, t('Image field formatters can have attributes.'));
}
/**
* Test use of a default image with an image field.
*/
function testImageFieldDefaultImage() {
// Create a new image field.
Dries Buytaert
committed
$field_name = strtolower($this->randomName());
$this->createImageField($field_name, 'article');
// Create a new node, with no images and verify that no images are
// displayed.
$node = $this->drupalCreateNode(array('type' => 'article'));
$this->drupalGet('node/' . $node->nid);
// Verify that no image is displayed on the page by checking for the class
// that would be used on the image field.
$this->assertNoPattern('<div class="(.*?)field-name-' . strtr($field_name, '_', '-') . '(.*?)">', t('No image displayed when no image is attached and no default image specified.'));
// Add a default image to the public imagefield instance.
$images = $this->drupalGetTestFiles('image');
$edit = array(
Angie Byron
committed
'files[field_settings_default_image]' => drupal_realpath($images[0]->uri),
);
$this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
// Clear field info cache so the new default image is detected.
field_info_cache_clear();
$field = field_info_field($field_name);
$image = file_load($field['settings']['default_image']);
$this->assertTrue($image->status == FILE_STATUS_PERMANENT, t('The default image status is permanent.'));
$default_output = theme('image', array('path' => $image->uri));
$this->drupalGet('node/' . $node->nid);
$this->assertRaw($default_output, t('Default image displayed when no user supplied image is present.'));
// Create a node with an image attached and ensure that the default image
// is not displayed.
$nid = $this->uploadNodeImage($images[1], $field_name, 'article');
$node = node_load($nid, NULL, TRUE);
$image_info = array(
'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
'width' => 40,
'height' => 20,
);
$image_output = theme('image', $image_info);
$this->drupalGet('node/' . $nid);
$this->assertNoRaw($default_output, t('Default image is not displayed when user supplied image is present.'));
$this->assertRaw($image_output, t('User supplied image is displayed.'));
// Remove default image from the field and make sure it is no longer used.
$edit = array(
'field[settings][default_image][fid]' => 0,
);
$this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
// Clear field info cache so the new default image is detected.
field_info_cache_clear();
$field = field_info_field($field_name);
$this->assertFalse($field['settings']['default_image'], t('Default image removed from field.'));
// Create an image field that uses the private:// scheme and test that the
// default image works as expected.
$private_field_name = strtolower($this->randomName());
$this->createImageField($private_field_name, 'article', array('uri_scheme' => 'private'));
// Add a default image to the new field.
$edit = array(
'files[field_settings_default_image]' => drupal_realpath($images[1]->uri),
);
$this->drupalPost('admin/structure/types/manage/article/fields/' . $private_field_name, $edit, t('Save settings'));
$private_field = field_info_field($private_field_name);
$image = file_load($private_field['settings']['default_image']);
$this->assertEqual('private', file_uri_scheme($image->uri), t('Default image uses private:// scheme.'));
$this->assertTrue($image->status == FILE_STATUS_PERMANENT, t('The default image status is permanent.'));
// Create a new node with no image attached and ensure that default private
// image is displayed.
$node = $this->drupalCreateNode(array('type' => 'article'));
$default_output = theme('image', array('path' => $image->uri));
$this->drupalGet('node/' . $node->nid);
$this->assertRaw($default_output, t('Default private image displayed when no user supplied image is present.'));
}
}
/**
* Test class to check for various validations.
*/
class ImageFieldValidateTestCase extends ImageFieldTestCase {
public static function getInfo() {
return array(
'name' => 'Image field validation tests',
'description' => 'Tests validation functions such as min/max resolution.',
'group' => 'Image',
);
}
/**
* Test min/max resolution settings.
*/
function testResolution() {
Dries Buytaert
committed
$field_name = strtolower($this->randomName());
Angie Byron
committed
$min_resolution = 50;
$max_resolution = 100;
$instance_settings = array(
Angie Byron
committed
'max_resolution' => $max_resolution . 'x' . $max_resolution,
'min_resolution' => $min_resolution . 'x' . $min_resolution,