508 lines
20 KiB
Plaintext
508 lines
20 KiB
Plaintext
<?php
|
|
// $Id$
|
|
|
|
/**
|
|
* @file
|
|
* Image module tests.
|
|
*/
|
|
|
|
|
|
/**
|
|
* 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()
|
|
*/
|
|
|
|
/**
|
|
* Tests the functions for generating paths and URLs for image styles.
|
|
*/
|
|
class ImageStylesPathAndUrlUnitTest 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() {
|
|
parent::setUp();
|
|
|
|
$this->style_name = 'style_foo';
|
|
image_style_save(array('name' => $this->style_name));
|
|
}
|
|
|
|
/**
|
|
* Test image_style_path().
|
|
*/
|
|
function testImageStylePath() {
|
|
$actual = image_style_path($this->style_name, 'public://foo/bar.gif');
|
|
$expected = 'public://styles/' . $this->style_name . '/foo/bar.gif';
|
|
$this->assertEqual($actual, $expected, t('Got the path for a file URI.'));
|
|
|
|
$actual = image_style_path($this->style_name, 'foo/bar.gif');
|
|
$expected = 'public://styles/' . $this->style_name . '/foo/bar.gif';
|
|
$this->assertEqual($actual, $expected, t('Got the path for a relative file path.'));
|
|
}
|
|
|
|
/**
|
|
* 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');
|
|
}
|
|
|
|
/**
|
|
* Test image_style_url().
|
|
*/
|
|
function _testImageStyleUrlAndPath($scheme) {
|
|
// Make the default scheme neither "public" nor "private" to verify the
|
|
// functions work for other than the default scheme.
|
|
variable_set('file_default_scheme', 'temporary');
|
|
$d = 'temporary://';
|
|
file_prepare_directory($d, FILE_CREATE_DIRECTORY);
|
|
|
|
// Create the directories for the styles.
|
|
$d = $scheme . '://styles/' . $this->style_name;
|
|
$status = file_prepare_directory($d, FILE_CREATE_DIRECTORY);
|
|
$this->assertNotIdentical(FALSE, $status, t('Created the directory for the generated images for the test style.' ));
|
|
|
|
// Create a working copy of the file.
|
|
$files = $this->drupalGetTestFiles('image');
|
|
$file = reset($files);
|
|
$image_info = image_get_info($file->uri);
|
|
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
|
$this->assertNotIdentical(FALSE, $original_uri, t('Created the generated image file.'));
|
|
|
|
// Get the URL of a file that has not been generated yet and try to access
|
|
// it before image_style_url has been called.
|
|
$generated_uri = $scheme . '://styles/' . $this->style_name . '/' . basename($original_uri);
|
|
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
|
|
$expected_generate_url = url('image/generate/' . $this->style_name . '/' . $scheme . '/' . basename($original_uri), array('absolute' => TRUE));
|
|
$this->drupalGet($expected_generate_url);
|
|
$this->assertResponse(403, t('Access to generate URL was denied.'));
|
|
|
|
// Check that a generate URL is returned.
|
|
$actual_generate_url = image_style_url($this->style_name, $original_uri);
|
|
$this->assertEqual($actual_generate_url, $expected_generate_url, t('Got the generate URL for a non-existent file.'));
|
|
|
|
// Fetch the URL that generates the file while another process appears to
|
|
// be generating the same file (this is signaled using a lock).
|
|
$lock_name = 'image_style_generate:' . $this->style_name . ':' . md5($original_uri);
|
|
$this->assertTrue(lock_acquire($lock_name), t('Lock was acquired.'));
|
|
$this->drupalGet($expected_generate_url);
|
|
$this->assertResponse(503, t('Service Unavailable response received.'));
|
|
$this->assertTrue($this->drupalGetHeader('Retry-After'), t('Retry-After header received.'));
|
|
lock_release($lock_name);
|
|
|
|
// Fetch the URL that generates the file.
|
|
$this->drupalGet($expected_generate_url);
|
|
$this->assertTrue(file_exists($generated_uri), t('Generated file was created.'));
|
|
$this->assertRaw(file_get_contents($generated_uri), t('URL returns expected file.'));
|
|
$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.'));
|
|
$this->assertTrue(lock_may_be_available($lock_name), t('Lock was released.'));
|
|
|
|
// Check that the URL points directly to the generated file.
|
|
$expected_generated_url = file_create_url($generated_uri);
|
|
$actual_generated_url = image_style_url($this->style_name, $original_uri);
|
|
$this->drupalGet($expected_generated_url);
|
|
$this->assertEqual($actual_generated_url, $expected_generated_url, t('Got the download URL for an existing file.'));
|
|
$this->assertRaw(file_get_contents($generated_uri), t('URL returns expected file.'));
|
|
$this->assertEqual($this->drupalGetHeader('Content-Type'), $image_info['mime_type'], t('Expected Content-Type was reported.'));
|
|
$this->assertEqual($this->drupalGetHeader('Content-Length'), $image_info['file_size'], t('Expected Content-Length was reported.'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
parent::setUp('image_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'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tests creation, deletion, and editing of image styles and effects.
|
|
*/
|
|
class ImageAdminStylesUnitTest extends DrupalWebTestCase {
|
|
|
|
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',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Implementation of setUp().
|
|
*/
|
|
function setUp() {
|
|
parent::setUp();
|
|
|
|
// Create an administrative user.
|
|
$this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer image styles'));
|
|
$this->drupalLogin($this->admin_user);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
$directory = file_directory_path() . '/styles/' . $style['name'];
|
|
return count(file_scan_directory($directory, '/.*/'));
|
|
}
|
|
|
|
/**
|
|
* 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));
|
|
$style_path = 'admin/config/media/image-styles/edit/' . $style_name;
|
|
$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,
|
|
);
|
|
$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.
|
|
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.
|
|
$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.
|
|
$this->drupalPost('admin/config/media/image-styles/delete/' . $style_name, array(), t('Delete'));
|
|
|
|
// Confirm the style directory has been removed.
|
|
$directory = file_directory_path() . '/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'])));
|
|
|
|
}
|
|
|
|
/**
|
|
* 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.'));
|
|
|
|
// 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.'));
|
|
|
|
// 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)));
|
|
|
|
// 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.'));
|
|
|
|
// 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);
|
|
|
|
// 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.'));
|
|
|
|
// 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.'));
|
|
|
|
// 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)));
|
|
|
|
// 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.'));
|
|
}
|
|
|
|
}
|