Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176

This commit is contained in:
Pantheon Automation 2015-08-17 17:00:26 -07:00 committed by Greg Anderson
commit 9921556621
13277 changed files with 1459781 additions and 0 deletions

View file

@ -0,0 +1,55 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\FileMoveTest.
*/
namespace Drupal\image\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\image\Entity\ImageStyle;
/**
* Tests the file move function for images and image styles.
*
* @group image
*/
class FileMoveTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('image');
/**
* Tests moving a randomly generated image.
*/
function testNormal() {
// Pick a file for testing.
$file = entity_create('file', (array) current($this->drupalGetTestFiles('image')));
// Create derivative image.
$styles = ImageStyle::loadMultiple();
$style = reset($styles);
$original_uri = $file->getFileUri();
$derivative_uri = $style->buildUri($original_uri);
$style->createDerivative($original_uri, $derivative_uri);
// Check if derivative image exists.
$this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.');
// Clone the object so we don't have to worry about the function changing
// our reference copy.
$desired_filepath = 'public://' . $this->randomMachineName();
$result = file_move(clone $file, $desired_filepath, FILE_EXISTS_ERROR);
// Check if image has been moved.
$this->assertTrue(file_exists($result->getFileUri()), 'Make sure image is moved successfully.');
// Check if derivative image has been flushed.
$this->assertFalse(file_exists($derivative_uri), 'Make sure derivative image has been flushed.');
}
}

View file

@ -0,0 +1,468 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageAdminStylesTest.
*/
namespace Drupal\image\Tests;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\image\Entity\ImageStyle;
use Drupal\image\ImageStyleInterface;
use Drupal\node\Entity\Node;
/**
* Tests creation, deletion, and editing of image styles and effects.
*
* @group image
*/
class ImageAdminStylesTest extends ImageFieldTestBase {
/**
* Given an image style, generate an image.
*/
function createSampleImage(ImageStyleInterface $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 $style->buildUrl($file_path) ? $file_path : FALSE;
}
/**
* Count the number of images currently create for a style.
*/
function getImageCount(ImageStyleInterface $style) {
return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
}
/**
* Test creating an image style with a numeric name and ensuring it can be
* applied to an image.
*/
function testNumericStyleName() {
$style_name = rand();
$style_label = $this->randomString();
$edit = array(
'name' => $style_name,
'label' => $style_label,
);
$this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
$this->assertRaw(t('Style %name was created.', array('%name' => $style_label)));
$options = image_style_options();
$this->assertTrue(array_key_exists($style_name, $options), format_string('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() {
$admin_path = 'admin/config/media/image-styles';
// Setup a style to be created and effects to add to it.
$style_name = strtolower($this->randomMachineName(10));
$style_label = $this->randomString();
$style_path = $admin_path . '/manage/' . $style_name;
$effect_edits = array(
'image_resize' => array(
'width' => 100,
'height' => 101,
),
'image_scale' => array(
'width' => 110,
'height' => 111,
'upscale' => 1,
),
'image_scale_and_crop' => array(
'width' => 120,
'height' => 121,
),
'image_crop' => array(
'width' => 130,
'height' => 131,
'anchor' => 'left-top',
),
'image_desaturate' => array(
// No options for desaturate.
),
'image_rotate' => array(
'degrees' => 5,
'random' => 1,
'bgcolor' => '#FFFF00',
),
);
// Add style form.
$edit = array(
'name' => $style_name,
'label' => $style_label,
);
$this->drupalPostForm($admin_path . '/add', $edit, t('Create new style'));
$this->assertRaw(t('Style %name was created.', array('%name' => $style_label)));
// Ensure that the expected entity operations are there.
$this->drupalGet($admin_path);
$this->assertLinkByHref($style_path);
$this->assertLinkByHref($style_path . '/flush');
$this->assertLinkByHref($style_path . '/delete');
// Add effect form.
// Add each sample effect to the style.
foreach ($effect_edits as $effect => $edit) {
$edit_data = array();
foreach ($edit as $field => $value) {
$edit_data['data[' . $field . ']'] = $value;
}
// Add the effect.
$this->drupalPostForm($style_path, array('new' => $effect), t('Add'));
if (!empty($edit)) {
$this->drupalPostForm(NULL, $edit_data, t('Add effect'));
}
}
// Load the saved image style.
$style = ImageStyle::load($style_name);
// Ensure that third party settings were added to the config entity.
// These are added by a hook_image_style_presave() implemented in
// image_module_test module.
$this->assertEqual('bar', $style->getThirdPartySetting('image_module_test', 'foo'), 'Third party settings were added to the image style.');
// Ensure that the image style URI matches our expected path.
$style_uri_path = $style->url();
$this->assertTrue(strpos($style_uri_path, $style_path) !== FALSE, 'The image style URI is correct.');
// Confirm that all effects on the image style have settings that match
// what was saved.
$uuids = array();
foreach ($style->getEffects() as $uuid => $effect) {
// Store the uuid for later use.
$uuids[$effect->getPluginId()] = $uuid;
$effect_configuration = $effect->getConfiguration();
foreach ($effect_edits[$effect->getPluginId()] as $field => $value) {
$this->assertEqual($value, $effect_configuration['data'][$field], SafeMarkup::format('The %field field in the %effect effect has the correct value of %value.', array('%field' => $field, '%effect' => $effect->getPluginId(), '%value' => $value)));
}
}
// Assert that every effect was saved.
foreach (array_keys($effect_edits) as $effect_name) {
$this->assertTrue(isset($uuids[$effect_name]), format_string(
'A %effect_name effect was saved with ID %uuid',
array(
'%effect_name' => $effect_name,
'%uuid' => $uuids[$effect_name],
)));
}
// 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);
$order_correct = TRUE;
$index = 0;
foreach ($style->getEffects() as $effect) {
if ($effect_edits_order[$index] != $effect->getPluginId()) {
$order_correct = FALSE;
}
$index++;
}
$this->assertTrue($order_correct, '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->randomMachineName(10));
$style_label = $this->randomMachineName();
$weight = count($effect_edits);
$edit = array(
'name' => $style_name,
'label' => $style_label,
);
foreach ($style->getEffects() as $uuid => $effect) {
$edit['effects[' . $uuid . '][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, format_string('Image style %style image %file successfully generated.', array('%style' => $style->label(), '%file' => $image_path)));
$this->drupalPostForm($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/manage/' . $style_name;
// Check that the URL was updated.
$this->drupalGet($style_path);
$this->assertTitle(t('Edit style @name | Drupal', array('@name' => $style_label)));
$this->assertResponse(200, format_string('Image style %original renamed to %new', array('%original' => $style->id(), '%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, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', array('%style' => $style->label())));
// Load the style by the new name with the new weights.
$style = ImageStyle::load($style_name);
// Confirm the new style order was saved.
$effect_edits_order = array_reverse($effect_edits_order);
$order_correct = TRUE;
$index = 0;
foreach ($style->getEffects() as $effect) {
if ($effect_edits_order[$index] != $effect->getPluginId()) {
$order_correct = FALSE;
}
$index++;
}
$this->assertTrue($order_correct, '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, format_string('Image style %style image %file successfully generated.', array('%style' => $style->label(), '%file' => $image_path)));
// Delete the 'image_crop' effect from the style.
$this->drupalPostForm($style_path . '/effects/' . $uuids['image_crop'] . '/delete', array(), t('Delete'));
// Confirm that the form submission was successful.
$this->assertResponse(200);
$image_crop_effect = $style->getEffect($uuids['image_crop']);
$this->assertRaw(t('The image effect %name has been deleted.', array('%name' => $image_crop_effect->label())));
// Confirm that there is no longer a link to the effect.
$this->assertNoLinkByHref($style_path . '/effects/' . $uuids['image_crop'] . '/delete');
// Refresh the image style information and verify that the effect was
// actually deleted.
$style = entity_load_unchanged('image_style', $style->id());
$this->assertFalse($style->getEffects()->has($uuids['image_crop']), format_string(
'Effect with ID %uuid no longer found on image style %style',
array(
'%uuid' => $uuids['image_crop'],
'%style' => $style->label(),
)));
// Additional test on Rotate effect, for transparent background.
$edit = array(
'data[degrees]' => 5,
'data[random]' => 0,
'data[bgcolor]' => '',
);
$this->drupalPostForm($style_path, array('new' => 'image_rotate'), t('Add'));
$this->drupalPostForm(NULL, $edit, t('Add effect'));
$style = entity_load_unchanged('image_style', $style_name);
$this->assertEqual(count($style->getEffects()), 6, 'Rotate effect with transparent background was added.');
// Style deletion form.
// Delete the style.
$this->drupalPostForm($style_path . '/delete', array(), t('Delete'));
// Confirm the style directory has been removed.
$directory = file_default_scheme() . '://styles/' . $style_name;
$this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', array('%style' => $style->label())));
$this->assertFalse(ImageStyle::load($style_name), format_string('Image style %style successfully deleted.', array('%style' => $style->label())));
}
/**
* Test deleting a style and choosing a replacement style.
*/
function testStyleReplacement() {
// Create a new style.
$style_name = strtolower($this->randomMachineName(10));
$style_label = $this->randomString();
$style = entity_create('image_style', array('name' => $style_name, 'label' => $style_label));
$style->save();
$style_path = 'admin/config/media/image-styles/manage/';
// Create an image field that uses the new style.
$field_name = strtolower($this->randomMachineName(10));
$this->createImageField($field_name, 'article');
entity_get_display('node', 'article', 'default')
->setComponent($field_name, array(
'type' => 'image',
'settings' => array('image_style' => $style_name),
))
->save();
// Create a new node with an image attached.
$test_image = current($this->drupalGetTestFiles('image'));
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
$node = Node::load($nid);
// Get node field original image URI.
$fid = $node->get($field_name)->target_id;
$original_uri = file_load($fid)->getFileUri();
// Test that image is displayed using newly created style.
$this->drupalGet('node/' . $nid);
$this->assertRaw($style->buildUrl($original_uri), format_string('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->randomMachineName(10));
$new_style_label = $this->randomString();
$edit = array(
'name' => $new_style_name,
'label' => $new_style_label,
);
$this->drupalPostForm($style_path . $style_name, $edit, t('Update style'));
$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)));
$this->drupalGet('node/' . $nid);
// Reload the image style using the new name.
$style = ImageStyle::load($new_style_name);
$this->assertRaw($style->buildUrl($original_uri), 'Image displayed using style replacement style.');
// Delete the style and choose a replacement style.
$edit = array(
'replacement' => 'thumbnail',
);
$this->drupalPostForm($style_path . $new_style_name . '/delete', $edit, t('Delete'));
$message = t('The image style %name has been deleted.', array('%name' => $new_style_label));
$this->assertRaw($message);
$replacement_style = ImageStyle::load('thumbnail');
$this->drupalGet('node/' . $nid);
$this->assertRaw($replacement_style->buildUrl($original_uri), 'Image displayed using style replacement style.');
}
/**
* Verifies that editing an image effect does not cause it to be duplicated.
*/
function testEditEffect() {
// Add a scale effect.
$style_name = 'test_style_effect_edit';
$this->drupalGet('admin/config/media/image-styles/add');
$this->drupalPostForm(NULL, array('label' => 'Test style effect edit', 'name' => $style_name), t('Create new style'));
$this->drupalPostForm(NULL, array('new' => 'image_scale_and_crop'), t('Add'));
$this->drupalPostForm(NULL, array('data[width]' => '300', 'data[height]' => '200'), t('Add effect'));
$this->assertText(t('Scale and crop 300×200'));
// There should normally be only one edit link on this page initially.
$this->clickLink(t('Edit'));
$this->drupalPostForm(NULL, array('data[width]' => '360', 'data[height]' => '240'), t('Update effect'));
$this->assertText(t('Scale and crop 360×240'));
// Check that the previous effect is replaced.
$this->assertNoText(t('Scale and crop 300×200'));
// Add another scale effect.
$this->drupalGet('admin/config/media/image-styles/add');
$this->drupalPostForm(NULL, array('label' => 'Test style scale edit scale', 'name' => 'test_style_scale_edit_scale'), t('Create new style'));
$this->drupalPostForm(NULL, array('new' => 'image_scale'), t('Add'));
$this->drupalPostForm(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
// Edit the scale effect that was just added.
$this->clickLink(t('Edit'));
$this->drupalPostForm(NULL, array('data[width]' => '24', 'data[height]' => '19'), t('Update effect'));
$this->drupalPostForm(NULL, array('new' => 'image_scale'), t('Add'));
// Add another scale effect and make sure both exist.
$this->drupalPostForm(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
$this->assertText(t('Scale 24×19'));
$this->assertText(t('Scale 12×19'));
// Try to edit a nonexistent effect.
$uuid = $this->container->get('uuid');
$this->drupalGet('admin/config/media/image-styles/manage/' . $style_name . '/effects/' . $uuid->generate());
$this->assertResponse(404);
}
/**
* Test flush user interface.
*/
public function testFlushUserInterface() {
$admin_path = 'admin/config/media/image-styles';
// Create a new style.
$style_name = strtolower($this->randomMachineName(10));
$style = entity_create('image_style', array('name' => $style_name, 'label' => $this->randomString()));
$style->save();
// Create an image to make sure it gets flushed.
$files = $this->drupalGetTestFiles('image');
$image_uri = $files[0]->uri;
$derivative_uri = $style->buildUri($image_uri);
$this->assertTrue($style->createDerivative($image_uri, $derivative_uri));
$this->assertEqual($this->getImageCount($style), 1);
// Go to image styles list page and check if the flush operation link
// exists.
$this->drupalGet($admin_path);
$flush_path = $admin_path . '/manage/' . $style_name . '/flush';
$this->assertLinkByHref($flush_path);
// Flush the image style derivatives using the user interface.
$this->drupalPostForm($flush_path, array(), t('Flush'));
// The derivative image file should have been deleted.
$this->assertEqual($this->getImageCount($style), 0);
}
/**
* Tests image style configuration import that does a delete.
*/
function testConfigImport() {
// Create a new style.
$style_name = strtolower($this->randomMachineName(10));
$style_label = $this->randomString();
$style = entity_create('image_style', array('name' => $style_name, 'label' => $style_label));
$style->save();
// Create an image field that uses the new style.
$field_name = strtolower($this->randomMachineName(10));
$this->createImageField($field_name, 'article');
entity_get_display('node', 'article', 'default')
->setComponent($field_name, array(
'type' => 'image',
'settings' => array('image_style' => $style_name),
))
->save();
// Create a new node with an image attached.
$test_image = current($this->drupalGetTestFiles('image'));
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
$node = Node::load($nid);
// Get node field original image URI.
$fid = $node->get($field_name)->target_id;
$original_uri = file_load($fid)->getFileUri();
// Test that image is displayed using newly created style.
$this->drupalGet('node/' . $nid);
$this->assertRaw($style->buildUrl($original_uri), format_string('Image displayed using style @style.', array('@style' => $style_name)));
// Copy config to staging, and delete the image style.
$staging = $this->container->get('config.storage.staging');
$active = $this->container->get('config.storage');
$this->copyConfig($active, $staging);
$staging->delete('image.style.' . $style_name);
$this->configImporter()->import();
$this->assertFalse(ImageStyle::load($style_name), 'Style deleted after config import.');
$this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.');
}
/**
* Tests access for the image style listing.
*/
public function testImageStyleAccess() {
$style = entity_create('image_style', array('name' => 'style_foo', 'label' => $this->randomString()));
$style->save();
$this->drupalGet('admin/config/media/image-styles');
$this->clickLink(t('Edit'));
$this->assertRaw(t('Select a new effect'));
}
}

View file

@ -0,0 +1,249 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageDimensionsTest.
*/
namespace Drupal\image\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Tests that images have correct dimensions when styled.
*
* @group image
*/
class ImageDimensionsTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('image', 'image_module_test');
protected $profile = 'testing';
/**
* Test styled image dimensions cumulatively.
*/
function testImageDimensions() {
$image_factory = $this->container->get('image.factory');
// Create a working copy of the file.
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
// Create a style.
/** @var $style \Drupal\image\ImageStyleInterface */
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
$style->save();
$generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
$url = $style->buildUrl($original_uri);
$variables = array(
'#theme' => 'image_style',
'#style_name' => 'test',
'#uri' => $original_uri,
'#width' => 40,
'#height' => 20,
);
// Verify that the original image matches the hard-coded values.
$image_file = $image_factory->get($original_uri);
$this->assertEqual($image_file->getWidth(), $variables['#width']);
$this->assertEqual($image_file->getHeight(), $variables['#height']);
// Scale an image that is wider than it is high.
$effect = array(
'id' => 'image_scale',
'data' => array(
'width' => 120,
'height' => 90,
'upscale' => TRUE,
),
'weight' => 0,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="120" height="60" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 120);
$this->assertEqual($image_file->getHeight(), 60);
// Rotate 90 degrees anticlockwise.
$effect = array(
'id' => 'image_rotate',
'data' => array(
'degrees' => -90,
'random' => FALSE,
),
'weight' => 1,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="60" height="120" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 60);
$this->assertEqual($image_file->getHeight(), 120);
// Scale an image that is higher than it is wide (rotated by previous effect).
$effect = array(
'id' => 'image_scale',
'data' => array(
'width' => 120,
'height' => 90,
'upscale' => TRUE,
),
'weight' => 2,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 45);
$this->assertEqual($image_file->getHeight(), 90);
// Test upscale disabled.
$effect = array(
'id' => 'image_scale',
'data' => array(
'width' => 400,
'height' => 200,
'upscale' => FALSE,
),
'weight' => 3,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 45);
$this->assertEqual($image_file->getHeight(), 90);
// Add a desaturate effect.
$effect = array(
'id' => 'image_desaturate',
'data' => array(),
'weight' => 4,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="45" height="90" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 45);
$this->assertEqual($image_file->getHeight(), 90);
// Add a random rotate effect.
$effect = array(
'id' => 'image_rotate',
'data' => array(
'degrees' => 180,
'random' => TRUE,
),
'weight' => 5,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
// Add a crop effect.
$effect = array(
'id' => 'image_crop',
'data' => array(
'width' => 30,
'height' => 30,
'anchor' => 'center-center',
),
'weight' => 6,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="30" height="30" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
$this->assertEqual($image_file->getWidth(), 30);
$this->assertEqual($image_file->getHeight(), 30);
// Rotate to a non-multiple of 90 degrees.
$effect = array(
'id' => 'image_rotate',
'data' => array(
'degrees' => 57,
'random' => FALSE,
),
'weight' => 7,
);
$effect_id = $style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" alt="" class="image-style-test" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$effect_plugin = $style->getEffect($effect_id);
$style->deleteImageEffect($effect_plugin);
// Ensure that an effect can unset dimensions.
$effect = array(
'id' => 'image_module_test_null',
'data' => array(),
'weight' => 8,
);
$style->addImageEffect($effect);
$style->save();
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" alt="" class="image-style-test" />');
}
/**
* Render an image style element.
*
* drupal_render() alters the passed $variables array by adding a new key
* '#printed' => TRUE. This prevents next call to re-render the element. We
* wrap drupal_render() in a helper protected method and pass each time a
* fresh array so that $variables won't get altered and the element is
* re-rendered each time.
*/
protected function getImageTag($variables) {
return str_replace("\n", NULL, \Drupal::service('renderer')->renderRoot($variables));
}
}

View file

@ -0,0 +1,186 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageEffectsTest.
*/
namespace Drupal\image\Tests;
use Drupal\system\Tests\Image\ToolkitTestBase;
/**
* Tests that the image effects pass parameters to the toolkit correctly.
*
* @group image
*/
class ImageEffectsTest extends ToolkitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('image', 'image_test', 'image_module_test');
/**
* The image effect manager.
*
* @var \Drupal\image\ImageEffectManager
*/
protected $manager;
protected function setUp() {
parent::setUp();
$this->manager = $this->container->get('plugin.manager.image.effect');
}
/**
* Test the image_resize_effect() function.
*/
function testResizeEffect() {
$this->assertImageEffect('image_resize', array(
'width' => 1,
'height' => 2,
));
$this->assertToolkitOperationsCalled(array('resize'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['resize'][0][0], 1, 'Width was passed correctly');
$this->assertEqual($calls['resize'][0][1], 2, 'Height was passed correctly');
}
/**
* Test the image_scale_effect() function.
*/
function testScaleEffect() {
// @todo: need to test upscaling.
$this->assertImageEffect('image_scale', array(
'width' => 10,
'height' => 10,
));
$this->assertToolkitOperationsCalled(array('scale'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['scale'][0][0], 10, 'Width was passed correctly');
$this->assertEqual($calls['scale'][0][1], 10, 'Height was based off aspect ratio and passed correctly');
}
/**
* Test the image_crop_effect() function.
*/
function testCropEffect() {
// @todo should test the keyword offsets.
$this->assertImageEffect('image_crop', array(
'anchor' => 'top-1',
'width' => 3,
'height' => 4,
));
$this->assertToolkitOperationsCalled(array('crop'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['crop'][0][0], 0, 'X was passed correctly');
$this->assertEqual($calls['crop'][0][1], 1, 'Y was passed correctly');
$this->assertEqual($calls['crop'][0][2], 3, 'Width was passed correctly');
$this->assertEqual($calls['crop'][0][3], 4, 'Height was passed correctly');
}
/**
* Tests the ConvertImageEffect plugin.
*/
function testConvertEffect() {
// Test jpeg.
$this->assertImageEffect('image_convert', array(
'extension' => 'jpeg',
));
$this->assertToolkitOperationsCalled(array('convert'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['convert'][0][0], 'jpeg', 'Extension was passed correctly');
}
/**
* Test the image_scale_and_crop_effect() function.
*/
function testScaleAndCropEffect() {
$this->assertImageEffect('image_scale_and_crop', array(
'width' => 5,
'height' => 10,
));
$this->assertToolkitOperationsCalled(array('scale_and_crop'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['scale_and_crop'][0][0], 5, 'Width was computed and passed correctly');
$this->assertEqual($calls['scale_and_crop'][0][1], 10, 'Height was computed and passed correctly');
}
/**
* Test the image_desaturate_effect() function.
*/
function testDesaturateEffect() {
$this->assertImageEffect('image_desaturate', array());
$this->assertToolkitOperationsCalled(array('desaturate'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual(count($calls['desaturate'][0]), 0, 'No parameters were passed.');
}
/**
* Test the image_rotate_effect() function.
*/
function testRotateEffect() {
// @todo: need to test with 'random' => TRUE
$this->assertImageEffect('image_rotate', array(
'degrees' => 90,
'bgcolor' => '#fff',
));
$this->assertToolkitOperationsCalled(array('rotate'));
// Check the parameters.
$calls = $this->imageTestGetAllCalls();
$this->assertEqual($calls['rotate'][0][0], 90, 'Degrees were passed correctly');
$this->assertEqual($calls['rotate'][0][1], '#fff', 'Background color was passed correctly');
}
/**
* 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.
$manager = $this->container->get('plugin.manager.image.effect');
$effects = $manager->getDefinitions();
$this->assertTrue($image_effect_definitions_called === 1, 'image_effect_definitions() generated data.');
// Second call should come from cache.
drupal_static_reset('image_module_test_image_effect_info_alter');
$cached_effects = $manager->getDefinitions();
$this->assertTrue($image_effect_definitions_called === 0, 'image_effect_definitions() returned data from cache.');
$this->assertTrue($effects == $cached_effects, 'Cached effects are the same as generated effects.');
}
/**
* Asserts the effect processing of an image effect plugin.
*
* @param string $effect_name
* The name of the image effect to test.
* @param array $data
* The data to pass to the image effect.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertImageEffect($effect_name, array $data) {
$effect = $this->manager->createInstance($effect_name, array('data' => $data));
return $this->assertTrue($effect->applyEffect($this->image), 'Function returned the expected value.');
}
}

View file

@ -0,0 +1,345 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageFieldDefaultImagesTest.
*/
namespace Drupal\image\Tests;
use Drupal\Component\Utility\Unicode;
use Drupal\file\Entity\File;
/**
* Tests setting up default images both to the field and field field.
*
* @group image
*/
class ImageFieldDefaultImagesTest extends ImageFieldTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field_ui');
/**
* Tests CRUD for fields and fields fields with default images.
*/
public function testDefaultImages() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Create files to use as the default images.
$files = $this->drupalGetTestFiles('image');
// Create 10 files so the default image fids are not a single value.
for ($i = 1; $i <= 10; $i++) {
$filename = $this->randomMachineName() . "$i";
$desired_filepath = 'public://' . $filename;
file_unmanaged_copy($files[0]->uri, $desired_filepath, FILE_EXISTS_ERROR);
$file = entity_create('file', array('uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename));
$file->save();
}
$default_images = array();
foreach (array('field', 'field', 'field2', 'field_new', 'field_new') as $image_target) {
$file = entity_create('file', (array) array_pop($files));
$file->save();
$default_images[$image_target] = $file;
}
// Create an image field and add an field to the article content type.
$field_name = strtolower($this->randomMachineName());
$storage_settings['default_image'] = array(
'uuid' => $default_images['field']->uuid(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
);
$field_settings['default_image'] = array(
'uuid' => $default_images['field']->uuid(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
);
$widget_settings = array(
'preview_image_style' => 'medium',
);
$field = $this->createImageField($field_name, 'article', $storage_settings, $field_settings, $widget_settings);
// The field default image id should be 2.
$this->assertEqual($field->getSetting('default_image')['uuid'], $default_images['field']->uuid());
// Also test \Drupal\field\Entity\FieldConfig::getSettings().
$this->assertEqual($field->getSettings()['default_image']['uuid'], $default_images['field']->uuid());
$field_storage = $field->getFieldStorageDefinition();
// The field default image id should be 1.
$this->assertEqual($field_storage->getSetting('default_image')['uuid'], $default_images['field']->uuid());
// Also test \Drupal\field\Entity\FieldStorageConfig::getSettings().
$this->assertEqual($field_storage->getSettings()['default_image']['uuid'], $default_images['field']->uuid());
// Add another field with another default image to the page content type.
$field2 = entity_create('field_config', array(
'field_storage' => $field_storage,
'bundle' => 'page',
'label' => $field->label(),
'required' => $field->isRequired(),
'settings' => array(
'default_image' => array(
'uuid' => $default_images['field2']->uuid(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
),
),
));
$field2->save();
$widget_settings = entity_get_form_display('node', $field->getTargetBundle(), 'default')->getComponent($field_name);
entity_get_form_display('node', 'page', 'default')
->setComponent($field_name, $widget_settings)
->save();
entity_get_display('node', 'page', 'default')
->setComponent($field_name)
->save();
// Confirm the defaults are present on the article field settings form.
$field_id = $field->id();
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id/storage");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field']->id(),
format_string(
'Article image field default equals expected file ID of @fid.',
array('@fid' => $default_images['field']->id())
)
);
// Confirm the defaults are present on the article field edit form.
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field']->id(),
format_string(
'Article image field field default equals expected file ID of @fid.',
array('@fid' => $default_images['field']->id())
)
);
// Confirm the defaults are present on the page field settings form.
$this->drupalGet("admin/structure/types/manage/page/fields/$field_id/storage");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field']->id(),
format_string(
'Page image field default equals expected file ID of @fid.',
array('@fid' => $default_images['field']->id())
)
);
// Confirm the defaults are present on the page field edit form.
$field2_id = $field2->id();
$this->drupalGet("admin/structure/types/manage/page/fields/$field2_id");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field2']->id(),
format_string(
'Page image field field default equals expected file ID of @fid.',
array('@fid' => $default_images['field2']->id())
)
);
// Confirm that the image default is shown for a new article node.
$article = $this->drupalCreateNode(array('type' => 'article'));
$article_built = $this->drupalBuildEntityView($article);
$this->assertEqual(
$article_built[$field_name][0]['#item']->target_id,
$default_images['field']->id(),
format_string(
'A new article node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field']->id())
)
);
// Confirm that the image default is shown for a new page node.
$page = $this->drupalCreateNode(array('type' => 'page'));
$page_built = $this->drupalBuildEntityView($page);
$this->assertEqual(
$page_built[$field_name][0]['#item']->target_id,
$default_images['field2']->id(),
format_string(
'A new page node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field2']->id())
)
);
// Upload a new default for the field storage.
$default_image_settings = $field_storage->getSetting('default_image');
$default_image_settings['uuid'] = $default_images['field_new']->uuid();
$field_storage->setSetting('default_image', $default_image_settings);
$field_storage->save();
// Confirm that the new default is used on the article field settings form.
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id/storage");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field_new']->id(),
format_string(
'Updated image field default equals expected file ID of @fid.',
array('@fid' => $default_images['field_new']->id())
)
);
// Reload the nodes and confirm the field field defaults are used.
$node_storage->resetCache(array($article->id(), $page->id()));
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
$this->assertEqual(
$article_built[$field_name][0]['#item']->target_id,
$default_images['field']->id(),
format_string(
'An existing article node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field']->id())
)
);
$this->assertEqual(
$page_built[$field_name][0]['#item']->target_id,
$default_images['field2']->id(),
format_string(
'An existing page node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field2']->id())
)
);
// Upload a new default for the article's field field.
$default_image_settings = $field->getSetting('default_image');
$default_image_settings['uuid'] = $default_images['field_new']->uuid();
$field->setSetting('default_image', $default_image_settings);
$field->save();
// Confirm the new field field default is used on the article field
// admin form.
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
$default_images['field_new']->id(),
format_string(
'Updated article image field field default equals expected file ID of @fid.',
array('@fid' => $default_images['field_new']->id())
)
);
// Reload the nodes.
$node_storage->resetCache(array($article->id(), $page->id()));
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
// Confirm the article uses the new default.
$this->assertEqual(
$article_built[$field_name][0]['#item']->target_id,
$default_images['field_new']->id(),
format_string(
'An existing article node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field_new']->id())
)
);
// Confirm the page remains unchanged.
$this->assertEqual(
$page_built[$field_name][0]['#item']->target_id,
$default_images['field2']->id(),
format_string(
'An existing page node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field2']->id())
)
);
// Confirm the default image is shown on the node form.
$file = File::load($default_images['field_new']->id());
$this->drupalGet('node/add/article');
$this->assertRaw($file->getFilename());
// Remove the instance default from articles.
$default_image_settings = $field->getSetting('default_image');
$default_image_settings['uuid'] = 0;
$field->setSetting('default_image', $default_image_settings);
$field->save();
// Confirm the article field field default has been removed.
$this->drupalGet("admin/structure/types/manage/article/fields/$field_id");
$this->assertFieldByXpath(
'//input[@name="settings[default_image][uuid][fids]"]',
'',
'Updated article image field field default has been successfully removed.'
);
// Reload the nodes.
$node_storage->resetCache(array($article->id(), $page->id()));
$article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id()));
$page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id()));
// Confirm the article uses the new field (not field) default.
$this->assertEqual(
$article_built[$field_name][0]['#item']->target_id,
$default_images['field_new']->id(),
format_string(
'An existing article node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field_new']->id())
)
);
// Confirm the page remains unchanged.
$this->assertEqual(
$page_built[$field_name][0]['#item']->target_id,
$default_images['field2']->id(),
format_string(
'An existing page node without an image has the expected default image file ID of @fid.',
array('@fid' => $default_images['field2']->id())
)
);
$non_image = $this->drupalGetTestFiles('text');
$this->drupalPostForm(NULL, array('files[settings_default_image_uuid]' => drupal_realpath($non_image[0]->uri)), t("Upload"));
$this->assertText('The specified file text-0.txt could not be uploaded.');
$this->assertText('Only files with the following extensions are allowed: png gif jpg jpeg.');
// Confirm the default image is shown on the node form.
$file = File::load($default_images['field_new']->id());
$this->drupalGet('node/add/article');
$this->assertRaw($file->getFilename());
}
/**
* Tests image field and field having an invalid default image.
*/
public function testInvalidDefaultImage() {
$field_storage = entity_create('field_storage_config', array(
'field_name' => Unicode::strtolower($this->randomMachineName()),
'entity_type' => 'node',
'type' => 'image',
'settings' => array(
'default_image' => array(
'uuid' => 100000,
)
),
));
$field_storage->save();
$settings = $field_storage->getSettings();
// The non-existent default image should not be saved.
$this->assertNull($settings['default_image']['uuid']);
$field = entity_create('field_config', array(
'field_storage' => $field_storage,
'bundle' => 'page',
'label' => $this->randomMachineName(),
'settings' => array(
'default_image' => array(
'uuid' => 100000,
)
),
));
$field->save();
$settings = $field->getSettings();
// The non-existent default image should not be saved.
$this->assertNull($settings['default_image']['uuid']);
}
}

View file

@ -0,0 +1,448 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageFieldDisplayTest.
*/
namespace Drupal\image\Tests;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\user\RoleInterface;
use Drupal\image\Entity\ImageStyle;
/**
* Tests the display of image fields.
*
* @group image
*/
class ImageFieldDisplayTest extends ImageFieldTestBase {
protected $dumpHeaders = TRUE;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field_ui');
/**
* 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(RoleInterface::ANONYMOUS_ID, array('access content' => FALSE));
$this->_testImageFieldFormatters('private');
}
/**
* Test image formatters on node display.
*/
function _testImageFieldFormatters($scheme) {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$field_name = strtolower($this->randomMachineName());
$field_settings = array('alt_field_required' => 0);
$instance = $this->createImageField($field_name, 'article', array('uri_scheme' => $scheme), $field_settings);
// Go to manage display page.
$this->drupalGet("admin/structure/types/manage/article/display");
// Test for existence of link to image styles configuration.
$this->drupalPostAjaxForm(NULL, array(), "{$field_name}_settings_edit");
$this->assertLinkByHref(\Drupal::url('entity.image_style.collection'), 0, 'Link to image styles configuration is found');
// Remove 'administer image styles' permission from testing admin user.
$admin_user_roles = $this->adminUser->getRoles(TRUE);
user_role_change_permissions(reset($admin_user_roles), array('administer image styles' => FALSE));
// Go to manage display page again.
$this->drupalGet("admin/structure/types/manage/article/display");
// Test for absence of link to image styles configuration.
$this->drupalPostAjaxForm(NULL, array(), "{$field_name}_settings_edit");
$this->assertNoLinkByHref(\Drupal::url('entity.image_style.collection'), 'Link to image styles configuration is absent when permissions are insufficient');
// Restore 'administer image styles' permission to testing admin user
user_role_change_permissions(reset($admin_user_roles), array('administer image styles' => TRUE));
// Create a new node with an image attached.
$test_image = current($this->drupalGetTestFiles('image'));
// Ensure that preview works.
$this->previewNodeImage($test_image, $field_name, 'article');
// After previewing, make the alt field required. It cannot be required
// during preview because the form validation will fail.
$instance->setSetting('alt_field_required', 1);
$instance->save();
// Create alt text for the image.
$alt = $this->randomMachineName();
// Save node.
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
$node_storage->resetCache(array($nid));
$node = $node_storage->load($nid);
// Test that the default formatter is being used.
$file = $node->{$field_name}->entity;
$image_uri = $file->getFileUri();
$image = array(
'#theme' => 'image',
'#uri' => $image_uri,
'#width' => 40,
'#height' => 20,
'#alt' => $alt,
);
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
// Test the image linked to file formatter.
$display_options = array(
'type' => 'image',
'settings' => array('image_link' => 'file'),
);
$display = entity_get_display('node', $node->getType(), 'default');
$display->setComponent($field_name, $display_options)
->save();
$image = array(
'#theme' => 'image',
'#uri' => $image_uri,
'#width' => 40,
'#height' => 20,
'#alt' => $alt,
);
$default_output = '<a href="' . file_create_url($image_uri) . '">' . $renderer->renderRoot($image) . '</a>';
$this->drupalGet('node/' . $nid);
$this->assertCacheTag($file->getCacheTags()[0]);
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
$this->assertRaw($default_output, '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)), 'File was downloaded successfully.');
if ($scheme == 'private') {
// Only verify HTTP headers when using private scheme and the headers are
// sent by Drupal.
$this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
$this->assertTrue(strstr($this->drupalGetHeader('Cache-Control'),'private') !== FALSE, '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', 'Access denied to original image as anonymous user.');
// Log in again.
$this->drupalLogin($this->adminUser);
}
// Test the image linked to content formatter.
$display_options['settings']['image_link'] = 'content';
$display->setComponent($field_name, $display_options)
->save();
$image = array(
'#theme' => 'image',
'#uri' => $image_uri,
'#width' => 40,
'#height' => 20,
);
$this->drupalGet('node/' . $nid);
$this->assertCacheTag($file->getCacheTags()[0]);
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
$elements = $this->xpath(
'//a[@href=:path]/img[@src=:url and @alt=:alt and @width=:width and @height=:height]',
array(
':path' => $node->url(),
':url' => file_create_url($image['#uri']),
':width' => $image['#width'],
':height' => $image['#height'],
':alt' => $alt,
)
);
$this->assertEqual(count($elements), 1, 'Image linked to content formatter displaying correctly on full node view.');
// Test the image style 'thumbnail' formatter.
$display_options['settings']['image_link'] = '';
$display_options['settings']['image_style'] = 'thumbnail';
$display->setComponent($field_name, $display_options)
->save();
// Ensure the derivative image is generated so we do not have to deal with
// image style callback paths.
$this->drupalGet(ImageStyle::load('thumbnail')->buildUrl($image_uri));
$image_style = array(
'#theme' => 'image_style',
'#uri' => $image_uri,
'#width' => 40,
'#height' => 20,
'#style_name' => 'thumbnail',
'#alt' => $alt,
);
$default_output = $renderer->renderRoot($image_style);
$this->drupalGet('node/' . $nid);
$image_style = ImageStyle::load('thumbnail');
$this->assertCacheTag($image_style->getCacheTags()[0]);
$this->assertRaw($default_output, '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(ImageStyle::load('thumbnail')->buildUrl($image_uri));
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
}
}
/**
* Tests for image field settings.
*/
function testImageFieldSettings() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$test_image = current($this->drupalGetTestFiles('image'));
list(, $test_image_extension) = explode('.', $test_image->filename);
$field_name = strtolower($this->randomMachineName());
$field_settings = array(
'alt_field' => 1,
'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(), $field_settings, $widget_settings);
// Verify that the min/max resolution set on the field are properly
// extracted, and displayed, on the image field's configuration form.
$this->drupalGet('admin/structure/types/manage/article/fields/' . $field->id());
$this->assertFieldByName('settings[max_resolution][x]', '100', 'Expected max resolution X value of 100.');
$this->assertFieldByName('settings[max_resolution][y]', '100', 'Expected max resolution Y value of 100.');
$this->assertFieldByName('settings[min_resolution][x]', '10', 'Expected min resolution X value of 10.');
$this->assertFieldByName('settings[min_resolution][y]', '10', 'Expected min resolution Y value of 10.');
$this->drupalGet('node/add/article');
$this->assertText(t('50 KB limit.'), 'Image widget max file size is displayed on article form.');
$this->assertText(t('Allowed types: @extensions.', array('@extensions' => $test_image_extension)), 'Image widget allowed file types displayed on article form.');
$this->assertText(t('Images must be larger than 10x10 pixels. Images larger than 100x100 pixels will be resized.'), '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.
// Create alt text for the image.
$alt = $this->randomMachineName();
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
$this->drupalGet('node/' . $nid . '/edit');
$this->assertFieldByName($field_name . '[0][alt]', '', 'Alt field displayed on article form.');
$this->assertFieldByName($field_name . '[0][title]', '', 'Title field displayed on article form.');
// Verify that the attached image is being previewed using the 'medium'
// style.
$node_storage->resetCache(array($nid));
$node = $node_storage->load($nid);
$file = $node->{$field_name}->entity;
$url = file_create_url(ImageStyle::load('medium')->buildUrl($file->getFileUri()));
$this->assertTrue($this->cssSelect('img[width=40][height=20][class=image-style-medium][src="' . $url . '"]'));
// Add alt/title fields to the image and verify that they are displayed.
$image = array(
'#theme' => 'image',
'#uri' => $file->getFileUri(),
'#alt' => $alt,
'#title' => $this->randomMachineName(),
'#width' => 40,
'#height' => 20,
);
$edit = array(
$field_name . '[0][alt]' => $image['#alt'],
$field_name . '[0][title]' => $image['#title'],
);
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->assertRaw($default_output, '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 . '[0][alt]' => $this->randomMachineName($test_size),
$field_name . '[0][title]' => $this->randomMachineName($test_size),
);
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$schema = $field->getFieldStorageDefinition()->getSchema();
$this->assertRaw(t('Alternative text cannot be longer than %max characters but is currently %length characters long.', array(
'%max' => $schema['columns']['alt']['length'],
'%length' => $test_size,
)));
$this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array(
'%max' => $schema['columns']['title']['length'],
'%length' => $test_size,
)));
// Set cardinality to unlimited and add upload a second image.
// The image widget is extending on the file widget, but the image field
// type does not have the 'display_field' setting which is expected by
// the file widget. This resulted in notices before when cardinality is not
// 1, so we need to make sure the file widget prevents these notices by
// providing all settings, even if they are not used.
// @see FileWidget::formMultipleElements().
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $field_name . '/storage', array('cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED), t('Save field settings'));
$edit = array(
'files[' . $field_name . '_1][]' => drupal_realpath($test_image->uri),
);
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
// Add the required alt text.
$this->drupalPostForm(NULL, [$field_name . '[1][alt]' => $alt], t('Save and keep published'));
$this->assertText(format_string('Article @title has been updated.', array('@title' => $node->getTitle())));
// Assert ImageWidget::process() calls FieldWidget::process().
$this->drupalGet('node/' . $node->id() . '/edit');
$edit = array(
'files[' . $field_name . '_2][]' => drupal_realpath($test_image->uri),
);
$this->drupalPostAjaxForm(NULL, $edit, $field_name . '_2_upload_button');
$this->assertNoRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-2-upload" name="files[' . $field_name . '_2][]" size="22" class="js-form-file form-file">');
$this->assertRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-3-upload" name="files[' . $field_name . '_3][]" size="22" class="js-form-file form-file">');
}
/**
* Test use of a default image with an image field.
*/
function testImageFieldDefaultImage() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Create a new image field.
$field_name = strtolower($this->randomMachineName());
$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->id());
// 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, '_', '-') . '(.*?)">', 'No image displayed when no image is attached and no default image specified.');
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
// Add a default image to the public image field.
$images = $this->drupalGetTestFiles('image');
$alt = $this->randomString(512);
$title = $this->randomString(1024);
$edit = array(
'files[settings_default_image_uuid]' => drupal_realpath($images[0]->uri),
'settings[default_image][alt]' => $alt,
'settings[default_image][title]' => $title,
);
$this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/storage", $edit, t('Save field settings'));
// Clear field definition cache so the new default image is detected.
\Drupal::entityManager()->clearCachedFieldDefinitions();
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
$default_image = $field_storage->getSetting('default_image');
$file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid']);
$this->assertTrue($file->isPermanent(), 'The default image status is permanent.');
$image = array(
'#theme' => 'image',
'#uri' => $file->getFileUri(),
'#alt' => $alt,
'#title' => $title,
'#width' => 40,
'#height' => 20,
);
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->drupalGet('node/' . $node->id());
$this->assertCacheTag($file->getCacheTags()[0]);
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
$this->assertRaw($default_output, '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.
// Create alt text for the image.
$alt = $this->randomMachineName();
$nid = $this->uploadNodeImage($images[1], $field_name, 'article', $alt);
$node_storage->resetCache(array($nid));
$node = $node_storage->load($nid);
$file = $node->{$field_name}->entity;
$image = array(
'#theme' => 'image',
'#uri' => $file->getFileUri(),
'#width' => 40,
'#height' => 20,
'#alt' => $alt,
);
$image_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->drupalGet('node/' . $nid);
$this->assertCacheTag($file->getCacheTags()[0]);
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
$this->assertNoRaw($default_output, 'Default image is not displayed when user supplied image is present.');
$this->assertRaw($image_output, 'User supplied image is displayed.');
// Remove default image from the field and make sure it is no longer used.
$edit = array(
'settings[default_image][uuid][fids]' => 0,
);
$this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/storage", $edit, t('Save field settings'));
// Clear field definition cache so the new default image is detected.
\Drupal::entityManager()->clearCachedFieldDefinitions();
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
$default_image = $field_storage->getSetting('default_image');
$this->assertFalse($default_image['uuid'], '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->randomMachineName());
$this->createImageField($private_field_name, 'article', array('uri_scheme' => 'private'));
// Add a default image to the new field.
$edit = array(
'files[settings_default_image_uuid]' => drupal_realpath($images[1]->uri),
'settings[default_image][alt]' => $alt,
'settings[default_image][title]' => $title,
);
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $private_field_name . '/storage', $edit, t('Save field settings'));
// Clear field definition cache so the new default image is detected.
\Drupal::entityManager()->clearCachedFieldDefinitions();
$private_field_storage = FieldStorageConfig::loadByName('node', $private_field_name);
$default_image = $private_field_storage->getSetting('default_image');
$file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid']);
$this->assertEqual('private', file_uri_scheme($file->getFileUri()), 'Default image uses private:// scheme.');
$this->assertTrue($file->isPermanent(), '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'));
$image = array(
'#theme' => 'image',
'#uri' => $file->getFileUri(),
'#alt' => $alt,
'#title' => $title,
'#width' => 40,
'#height' => 20,
);
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->drupalGet('node/' . $node->id());
$this->assertCacheTag($file->getCacheTags()[0]);
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
$this->assertRaw($default_output, 'Default private image displayed when no user supplied image is present.');
}
}

View file

@ -0,0 +1,152 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageFieldTestBase.
*/
namespace Drupal\image\Tests;
use Drupal\simpletest\WebTestBase;
/**
* TODO: Test the following functions.
*
* image.effects.inc:
* image_style_generate()
* \Drupal\image\ImageStyleInterface::createDerivative()
*
* image.module:
* image_style_options()
* \Drupal\image\ImageStyleInterface::flush()
* image_filter_keyword()
*/
/**
* This class provides methods specifically for testing Image's field handling.
*/
abstract class ImageFieldTestBase extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'image', 'field_ui', 'image_module_test');
/**
* An user with permissions to administer content types and image styles.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
protected function setUp() {
parent::setUp();
// Create Basic page and Article node types.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
}
$this->adminUser = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer node fields', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles', 'administer node display'));
$this->drupalLogin($this->adminUser);
}
/**
* Create a new image field.
*
* @param string $name
* The name of the new field (all lowercase), exclude the "field_" prefix.
* @param string $type_name
* The node type that this field will be added to.
* @param array $storage_settings
* A list of field storage settings that will be added to the defaults.
* @param array $field_settings
* A list of instance settings that will be added to the instance defaults.
* @param array $widget_settings
* A list of widget settings that will be added to the widget defaults.
*/
function createImageField($name, $type_name, $storage_settings = array(), $field_settings = array(), $widget_settings = array()) {
entity_create('field_storage_config', array(
'field_name' => $name,
'entity_type' => 'node',
'type' => 'image',
'settings' => $storage_settings,
'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1,
))->save();
$field_config = entity_create('field_config', array(
'field_name' => $name,
'label' => $name,
'entity_type' => 'node',
'bundle' => $type_name,
'required' => !empty($field_settings['required']),
'settings' => $field_settings,
));
$field_config->save();
entity_get_form_display('node', $type_name, 'default')
->setComponent($name, array(
'type' => 'image_image',
'settings' => $widget_settings,
))
->save();
entity_get_display('node', $type_name, 'default')
->setComponent($name)
->save();
return $field_config;
}
/**
* Preview an image in a node.
*
* @param \Drupal\Core\Image\ImageInterface $image
* A file object representing the image to upload.
* @param string $field_name
* Name of the image field the image should be attached to.
* @param string $type
* The type of node to create.
*/
function previewNodeImage($image, $field_name, $type) {
$edit = array(
'title[0][value]' => $this->randomMachineName(),
);
$edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri);
$this->drupalPostForm('node/add/' . $type, $edit, t('Preview'));
}
/**
* 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.
* @param $alt
* The alt text for the image. Use if the field settings require alt text.
*/
function uploadNodeImage($image, $field_name, $type, $alt = '') {
$edit = array(
'title[0][value]' => $this->randomMachineName(),
);
$edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri);
$this->drupalPostForm('node/add/' . $type, $edit, t('Save and publish'));
if ($alt) {
// Add alt text.
$this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save and publish'));
}
// 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;
}
}

View file

@ -0,0 +1,109 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageFieldValidateTest.
*/
namespace Drupal\image\Tests;
/**
* Tests validation functions such as min/max resolution.
*
* @group image
*/
class ImageFieldValidateTest extends ImageFieldTestBase {
/**
* Test min/max resolution settings.
*/
function testResolution() {
$field_name = strtolower($this->randomMachineName());
$min_resolution = 50;
$max_resolution = 100;
$field_settings = array(
'max_resolution' => $max_resolution . 'x' . $max_resolution,
'min_resolution' => $min_resolution . 'x' . $min_resolution,
'alt_field' => 0,
);
$this->createImageField($field_name, 'article', array(), $field_settings);
// We want a test image that is too small, and a test image that is too
// big, so cycle through test image files until we have what we need.
$image_that_is_too_big = FALSE;
$image_that_is_too_small = FALSE;
$image_factory = $this->container->get('image.factory');
foreach ($this->drupalGetTestFiles('image') as $image) {
$image_file = $image_factory->get($image->uri);
if ($image_file->getWidth() > $max_resolution) {
$image_that_is_too_big = $image;
}
if ($image_file->getWidth() < $min_resolution) {
$image_that_is_too_small = $image;
}
if ($image_that_is_too_small && $image_that_is_too_big) {
break;
}
}
$this->uploadNodeImage($image_that_is_too_small, $field_name, 'article');
$this->assertRaw(t('The specified file %name could not be uploaded.', array('%name' => $image_that_is_too_small->filename)));
$this->assertRaw(t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => '50x50')));
$this->uploadNodeImage($image_that_is_too_big, $field_name, 'article');
$this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'));
}
/**
* Test that required alt/title fields gets validated right.
*/
function testRequiredAttributes() {
$field_name = strtolower($this->randomMachineName());
$field_settings = array(
'alt_field' => 1,
'alt_field_required' => 1,
'title_field' => 1,
'title_field_required' => 1,
'required' => 1,
);
$instance = $this->createImageField($field_name, 'article', array(), $field_settings);
$images = $this->drupalGetTestFiles('image');
// Let's just use the first image.
$image = $images[0];
$this->uploadNodeImage($image, $field_name, 'article');
// Look for form-required for the alt text.
$elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
$this->assertTrue(isset($elements[0]),'Required marker is shown for the required alt text.');
$elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
$this->assertTrue(isset($elements[0]), 'Required marker is shown for the required title text.');
$this->assertText(t('Alternative text field is required.'));
$this->assertText(t('Title field is required.'));
$instance->setSetting('alt_field_required', 0);
$instance->setSetting('title_field_required', 0);
$instance->save();
$edit = array(
'title[0][value]' => $this->randomMachineName(),
);
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
$this->assertNoText(t('Alternative text field is required.'));
$this->assertNoText(t('Title field is required.'));
$instance->setSetting('required', 0);
$instance->setSetting('alt_field_required', 1);
$instance->setSetting('title_field_required', 1);
$instance->save();
$edit = array(
'title[0][value]' => $this->randomMachineName(),
);
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
$this->assertNoText(t('Alternative text field is required.'));
$this->assertNoText(t('Title field is required.'));
}
}

View file

@ -0,0 +1,51 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageImportTest.
*/
namespace Drupal\image\Tests;
use Drupal\image\Entity\ImageStyle;
use Drupal\simpletest\KernelTestBase;
/**
* Tests config import for Image styles.
*
* @group image
*/
class ImageImportTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'image', 'image_module_test'];
/**
* Tests importing image styles.
*/
public function testImport() {
$style = ImageStyle::create([
'name' => 'test'
]);
$style->addImageEffect(['id' => 'image_module_test_null']);
$style->addImageEffect(['id' => 'image_module_test_null']);
$style->save();
$this->assertEqual(count($style->getEffects()), 2);
$uuid = \Drupal::service('uuid')->generate();
$style->set('effects', [
$uuid => [
'id' => 'image_module_test_null',
],
]);
$style->save();
$style = ImageStyle::load('test');
$this->assertEqual(count($style->getEffects()), 1);
}
}

View file

@ -0,0 +1,124 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageItemTest.
*/
namespace Drupal\image\Tests;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Tests\FieldUnitTestBase;
/**
* Tests using entity fields of the image field type.
*
* @group image
*/
class ImageItemTest extends FieldUnitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file', 'image');
/**
* Created file entity.
*
* @var \Drupal\file\Entity\File
*/
protected $image;
/**
* @var \Drupal\Core\Image\ImageFactory
*/
protected $imageFactory;
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
$this->installSchema('file', array('file_usage'));
entity_create('field_storage_config', array(
'entity_type' => 'entity_test',
'field_name' => 'image_test',
'type' => 'image',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
))->save();
entity_create('field_config', array(
'entity_type' => 'entity_test',
'field_name' => 'image_test',
'bundle' => 'entity_test',
))->save();
file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = entity_create('file', array(
'uri' => 'public://example.jpg',
));
$this->image->save();
$this->imageFactory = $this->container->get('image.factory');
}
/**
* Tests using entity fields of the image field type.
*/
public function testImageItem() {
// Create a test entity with the image field set.
$entity = entity_create('entity_test');
$entity->image_test->target_id = $this->image->id();
$entity->image_test->alt = $alt = $this->randomMachineName();
$entity->image_test->title = $title = $this->randomMachineName();
$entity->name->value = $this->randomMachineName();
$entity->save();
$entity = entity_load('entity_test', $entity->id());
$this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.');
$this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.');
$this->assertEqual($entity->image_test->target_id, $this->image->id());
$this->assertEqual($entity->image_test->alt, $alt);
$this->assertEqual($entity->image_test->title, $title);
$image = $this->imageFactory->get('public://example.jpg');
$this->assertEqual($entity->image_test->width, $image->getWidth());
$this->assertEqual($entity->image_test->height, $image->getHeight());
$this->assertEqual($entity->image_test->entity->id(), $this->image->id());
$this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid());
// Make sure the computed entity reflects updates to the referenced file.
file_unmanaged_copy(\Drupal::root() . '/core/misc/feed.png', 'public://example-2.jpg');
$image2 = entity_create('file', array(
'uri' => 'public://example-2.jpg',
));
$image2->save();
$entity->image_test->target_id = $image2->id();
$entity->image_test->alt = $new_alt = $this->randomMachineName();
// The width and height is only updated when width is not set.
$entity->image_test->width = NULL;
$entity->save();
$this->assertEqual($entity->image_test->entity->id(), $image2->id());
$this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri());
$image = $this->imageFactory->get('public://example-2.jpg');
$this->assertEqual($entity->image_test->width, $image->getWidth());
$this->assertEqual($entity->image_test->height, $image->getHeight());
$this->assertEqual($entity->image_test->alt, $new_alt);
// Check that the image item can be set to the referenced file directly.
$entity->image_test = $this->image;
$this->assertEqual($entity->image_test->target_id, $this->image->id());
// Delete the image and try to save the entity again.
$this->image->delete();
$entity = entity_create('entity_test', array('mame' => $this->randomMachineName()));
$entity->save();
// Test the generateSampleValue() method.
$entity = entity_create('entity_test');
$entity->image_test->generateSampleItems();
$this->entityValidateAndSave($entity);
}
}

View file

@ -0,0 +1,114 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageStyleFlushTest.
*/
namespace Drupal\image\Tests;
use Drupal\image\Entity\ImageStyle;
/**
* Tests flushing of image styles.
*
* @group image
*/
class ImageStyleFlushTest extends ImageFieldTestBase {
/**
* Given an image style and a wrapper, generate an image.
*/
function createSampleImage($style, $wrapper) {
static $file;
if (!isset($file)) {
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
}
// Make sure we have an image in our wrapper testing file directory.
$source_uri = file_unmanaged_copy($file->uri, $wrapper . '://');
// Build the derivative image.
$derivative_uri = $style->buildUri($source_uri);
$derivative = $style->createDerivative($source_uri, $derivative_uri);
return $derivative ? $derivative_uri : FALSE;
}
/**
* Count the number of images currently created for a style in a wrapper.
*/
function getImageCount($style, $wrapper) {
return count(file_scan_directory($wrapper . '://styles/' . $style->id(), '/.*/'));
}
/**
* General test to flush a style.
*/
function testFlush() {
// Setup a style to be created and effects to add to it.
$style_name = strtolower($this->randomMachineName(10));
$style_label = $this->randomString();
$style_path = 'admin/config/media/image-styles/manage/' . $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,
),
);
// Add style form.
$edit = array(
'name' => $style_name,
'label' => $style_label,
);
$this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
// Add each sample effect to the style.
foreach ($effect_edits as $effect => $edit) {
// Add the effect.
$this->drupalPostForm($style_path, array('new' => $effect), t('Add'));
if (!empty($edit)) {
$this->drupalPostForm(NULL, $edit, t('Add effect'));
}
}
// Load the saved image style.
$style = ImageStyle::load($style_name);
// Create an image for the 'public' wrapper.
$image_path = $this->createSampleImage($style, 'public');
// Expecting to find 2 images, one is the sample.png image shown in
// image style preview.
$this->assertEqual($this->getImageCount($style, 'public'), 2, format_string('Image style %style image %file successfully generated.', array('%style' => $style->label(), '%file' => $image_path)));
// Create an image for the 'private' wrapper.
$image_path = $this->createSampleImage($style, 'private');
$this->assertEqual($this->getImageCount($style, 'private'), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style->label(), '%file' => $image_path)));
// Remove the 'image_scale' effect and updates the style, which in turn
// forces an image style flush.
$style_path = 'admin/config/media/image-styles/manage/' . $style->id();
$uuids = array();
foreach ($style->getEffects() as $uuid => $effect) {
$uuids[$effect->getPluginId()] = $uuid;
}
$this->drupalPostForm($style_path . '/effects/' . $uuids['image_scale'] . '/delete', array(), t('Delete'));
$this->assertResponse(200);
$this->drupalPostForm($style_path, array(), t('Update style'));
$this->assertResponse(200);
// Post flush, expected 1 image in the 'public' wrapper (sample.png).
$this->assertEqual($this->getImageCount($style, 'public'), 1, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style->label(), '%wrapper' => 'public')));
// Post flush, expected no image in the 'private' wrapper.
$this->assertEqual($this->getImageCount($style, 'private'), 0, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style->label(), '%wrapper' => 'private')));
}
}

View file

@ -0,0 +1,229 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageStylesPathAndUrlTest.
*/
namespace Drupal\image\Tests;
use Drupal\simpletest\WebTestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests the functions for generating paths and URLs for image styles.
*
* @group image
*/
class ImageStylesPathAndUrlTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('image', 'image_module_test');
/**
* @var \Drupal\image\ImageStyleInterface
*/
protected $style;
protected function setUp() {
parent::setUp();
$this->style = entity_create('image_style', array('name' => 'style_foo', 'label' => $this->randomString()));
$this->style->save();
}
/**
* Tests \Drupal\image\ImageStyleInterface::buildUri().
*/
function testImageStylePath() {
$scheme = 'public';
$actual = $this->style->buildUri("$scheme://foo/bar.gif");
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, 'Got the path for a file URI.');
$actual = $this->style->buildUri('foo/bar.gif');
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
}
/**
* Tests an image style URL using the "public://" scheme.
*/
function testImageStyleUrlAndPathPublic() {
$this->doImageStyleUrlAndPathTests('public');
}
/**
* Tests an image style URL using the "private://" scheme.
*/
function testImageStyleUrlAndPathPrivate() {
$this->doImageStyleUrlAndPathTests('private');
}
/**
* Tests an image style URL with the "public://" scheme and unclean URLs.
*/
function testImageStyleUrlAndPathPublicUnclean() {
$this->doImageStyleUrlAndPathTests('public', FALSE);
}
/**
* Tests an image style URL with the "private://" schema and unclean URLs.
*/
function testImageStyleUrlAndPathPrivateUnclean() {
$this->doImageStyleUrlAndPathTests('private', FALSE);
}
/**
* Tests an image style URL with a file URL that has an extra slash in it.
*/
function testImageStyleUrlExtraSlash() {
$this->doImageStyleUrlAndPathTests('public', TRUE, TRUE);
}
/**
* Tests that an invalid source image returns a 404.
*/
function testImageStyleUrlForMissingSourceImage() {
$non_existent_uri = 'public://foo.png';
$generated_url = $this->style->buildUrl($non_existent_uri);
$this->drupalGet($generated_url);
$this->assertResponse(404, 'Accessing an image style URL with a source image that does not exist provides a 404 error response.');
}
/**
* Tests building an image style URL.
*/
function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
$this->prepareRequestForGenerator($clean_url);
// Make the default scheme neither "public" nor "private" to verify the
// functions work for other than the default scheme.
$this->config('system.file')->set('default_scheme', 'temporary')->save();
// Create the directories for the styles.
$directory = $scheme . '://styles/' . $this->style->id();
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
// Create a working copy of the file.
$files = $this->drupalGetTestFiles('image');
$file = array_shift($files);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download().
\Drupal::state()->set('image.test_file_download', $original_uri);
$this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.');
// Get the URL of a file that has not been generated and try to create it.
$generated_uri = $this->style->buildUri($original_uri);
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
// Ensure that the tests still pass when the file is generated by accessing
// a poorly constructed (but still valid) file URL that has an extra slash
// in it.
if ($extra_slash) {
$modified_uri = str_replace('://', ':///', $original_uri);
$this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
$generate_url = $this->style->buildUrl($modified_uri, $clean_url);
}
if (!$clean_url) {
$this->assertTrue(strpos($generate_url, 'index.php/') !== FALSE, 'When using non-clean URLS, the system path contains the script name.');
}
// 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 with 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 with a missing token.');
// Check that the generated URL is the same when we pass in a relative path
// rather than a URI. We need to temporarily switch the default scheme to
// match the desired scheme before testing this, then switch it back to the
// "temporary" scheme used throughout this test afterwards.
$this->config('system.file')->set('default_scheme', $scheme)->save();
$relative_path = file_uri_target($original_uri);
$generate_url_from_relative_path = $this->style->buildUrl($relative_path, $clean_url);
$this->assertEqual($generate_url, $generate_url_from_relative_path);
$this->config('system.file')->set('default_scheme', 'temporary')->save();
// Fetch the URL that generates the file.
$this->drupalGet($generate_url);
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.');
$image = $this->container->get('image.factory')->get($generated_uri);
$this->assertEqual($this->drupalGetHeader('Content-Type'), $image->getMimeType(), 'Expected Content-Type was reported.');
$this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize(), 'Expected Content-Length was reported.');
if ($scheme == 'private') {
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
$this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.');
$this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
// Make sure that a second request to the already existing derivative
// works too.
$this->drupalGet($generate_url);
$this->assertResponse(200, 'Image was generated at the URL.');
// Make sure that access is denied for existing style files if we do not
// have access.
\Drupal::state()->delete('image.test_file_download');
$this->drupalGet($generate_url);
$this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
// 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->id() . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
$this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
$generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess);
$this->drupalGet($generate_url_noaccess);
$this->assertResponse(403, '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 ) {
$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.
$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.');
}
}
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 with an invalid token.');
}
// Allow insecure image derivatives to be created for the remainder of this
// test.
$this->config('image.settings')->set('allow_insecure_derivatives', TRUE)->save();
// Create another working copy of the file.
$files = $this->drupalGetTestFiles('image');
$file = array_shift($files);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download().
\Drupal::state()->set('image.test_file_download', $original_uri);
// Suppress the security token in the URL, then get the URL of a file that
// has not been created and try to create it. Check that the security token
// is not present in the URL but that the image is still accessible.
$this->config('image.settings')->set('suppress_itok_output', TRUE)->save();
$generated_uri = $this->style->buildUri($original_uri);
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
$this->assertIdentical(strpos($generate_url, IMAGE_DERIVATIVE_TOKEN . '='), FALSE, 'The security token does not appear in the image style URL.');
$this->drupalGet($generate_url);
$this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
}
}

View file

@ -0,0 +1,220 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\ImageThemeFunctionTest.
*/
namespace Drupal\image\Tests;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\simpletest\WebTestBase;
/**
* Tests image theme functions.
*
* @group image
*/
class ImageThemeFunctionTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('image', 'entity_test');
/**
* Created file entity.
*
* @var \Drupal\file\Entity\File
*/
protected $image;
/**
* @var \Drupal\Core\Image\ImageFactory
*/
protected $imageFactory;
protected function setUp() {
parent::setUp();
entity_create('field_storage_config', array(
'entity_type' => 'entity_test',
'field_name' => 'image_test',
'type' => 'image',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
))->save();
entity_create('field_config', array(
'entity_type' => 'entity_test',
'field_name' => 'image_test',
'bundle' => 'entity_test',
))->save();
file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = entity_create('file', array(
'uri' => 'public://example.jpg',
));
$this->image->save();
$this->imageFactory = $this->container->get('image.factory');
}
/**
* Tests usage of the image field formatters.
*/
function testImageFormatterTheme() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
// Create an image.
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
// Create a style.
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
$style->save();
$url = $style->buildUrl($original_uri);
// Create a test entity with the image field set.
$entity = entity_create('entity_test');
$entity->image_test->target_id = $this->image->id();
$entity->image_test->alt = NULL;
$entity->image_test->uri = $original_uri;
$image = $this->imageFactory->get('public://example.jpg');
$entity->save();
// Create the base element that we'll use in the tests below.
$path = $this->randomMachineName();
$base_element = array(
'#theme' => 'image_formatter',
'#image_style' => 'test',
'#item' => $entity->image_test,
'#url' => Url::fromUri('base:' . $path),
);
// Test using theme_image_formatter() with a NULL value for the alt option.
$element = $base_element;
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height]', array(':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()));
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders with a NULL value for the alt option.');
// Test using theme_image_formatter() without an image title, alt text, or
// link options.
$element = $base_element;
$element['#item']->alt = '';
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()));
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders without title, alt, or path options.');
// Link the image to a fragment on the page, and not a full URL.
$fragment = $this->randomMachineName();
$element = $base_element;
$element['#url'] = Url::fromRoute('<none>', [], ['fragment' => $fragment]);
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//a[@href=:fragment]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(
':fragment' => '#' . $fragment,
':url' => $url,
':width' => $image->getWidth(),
':height' => $image->getHeight()
));
$this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders a link fragment.');
}
/**
* Tests usage of the image style theme function.
*/
function testImageStyleTheme() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
// Create an image.
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
// Create a style.
$style = entity_create('image_style', array('name' => 'image_test', 'label' => 'Test'));
$style->save();
$url = $style->buildUrl($original_uri);
// Create the base element that we'll use in the tests below.
$base_element = array(
'#theme' => 'image_style',
'#style_name' => 'image_test',
'#uri' => $original_uri,
);
$element = $base_element;
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url and @alt=""]', array(':url' => $url));
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly.');
// Test using theme_image_style() with a NULL value for the alt option.
$element = $base_element;
$element['#alt'] = NULL;
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url]', array(':url' => $url));
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly with a NULL value for the alt option.');
}
/**
* Tests image alt attribute functionality.
*/
function testImageAltFunctionality() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
// Test using alt directly with alt attribute.
$image_with_alt_property = array(
'#theme' => 'image',
'#uri' => '/core/themes/bartik/logo.svg',
'#alt' => 'Regular alt',
'#title' => 'Test title',
'#width' => '50%',
'#height' => '50%',
'#attributes' => array('class' => 'image-with-regular-alt', 'id' => 'my-img'),
);
$this->setRawContent($renderer->renderRoot($image_with_alt_property));
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', array(":class" => "image-with-regular-alt", ":alt" => "Regular alt"));
$this->assertEqual(count($elements), 1, 'Regular alt displays correctly');
// Test using alt attribute inside attributes.
$image_with_alt_attribute_alt_attribute = array(
'#theme' => 'image',
'#uri' => '/core/themes/bartik/logo.svg',
'#width' => '50%',
'#height' => '50%',
'#attributes' => array(
'class' => 'image-with-attribute-alt',
'id' => 'my-img',
'title' => 'New test title',
'alt' => 'Attribute alt',
),
);
$this->setRawContent($renderer->renderRoot($image_with_alt_attribute_alt_attribute));
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', array(":class" => "image-with-attribute-alt", ":alt" => "Attribute alt"));
$this->assertEqual(count($elements), 1, 'Attribute alt displays correctly');
// Test using alt attribute as property and inside attributes.
$image_with_alt_attribute_both = array(
'#theme' => 'image',
'#uri' => '/core/themes/bartik/logo.svg',
'#width' => '50%',
'#height' => '50%',
'#alt' => 'Kitten sustainable',
'#attributes' => array(
'class' => 'image-with-attribute-alt',
'id' => 'my-img',
'title' => 'New test title',
'alt' => 'Attribute alt',
),
);
$this->setRawContent($renderer->renderRoot($image_with_alt_attribute_both));
$elements = $this->xpath('//img[contains(@class, class) and contains(@alt, :alt)]', array(":class" => "image-with-attribute-alt", ":alt" => "Attribute alt"));
$this->assertEqual(count($elements), 1, 'Attribute alt overrides alt property if both set.');
}
}

View file

@ -0,0 +1,97 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\Views\ImageViewsDataTest.
*/
namespace Drupal\image\Tests\Views;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
use Drupal\views\Tests\ViewUnitTestBase;
use Drupal\views\Views;
/**
* Tests image views data.
*
* @group image
*/
class ImageViewsDataTest extends ViewUnitTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('image', 'file', 'views', 'entity_test', 'user', 'field');
/**
* Tests views data generated for image field relationship.
*
* @see image_field_views_data()
* @see image_field_views_data_views_data_alter()
*/
public function testRelationshipViewsData() {
// Create image field to entity_test.
FieldStorageConfig::create(array(
'entity_type' => 'entity_test',
'field_name' => 'field_base_image',
'type' => 'image',
))->save();
FieldConfig::create(array(
'entity_type' => 'entity_test',
'field_name' => 'field_base_image',
'bundle' => 'entity_test',
))->save();
// Check the generated views data.
$views_data = Views::viewsData()->get('entity_test__field_base_image');
$relationship = $views_data['field_base_image_target_id']['relationship'];
$this->assertEqual($relationship['id'], 'standard');
$this->assertEqual($relationship['base'], 'file_managed');
$this->assertEqual($relationship['base field'], 'fid');
$this->assertEqual($relationship['entity type'], 'file');
// Check the backwards reference.
$views_data = Views::viewsData()->get('file_managed');
$relationship = $views_data['reverse_field_base_image_entity_test']['relationship'];
$this->assertEqual($relationship['id'], 'entity_reverse');
$this->assertEqual($relationship['base'], 'entity_test');
$this->assertEqual($relationship['base field'], 'id');
$this->assertEqual($relationship['field table'], 'entity_test__field_base_image');
$this->assertEqual($relationship['field field'], 'field_base_image_target_id');
$this->assertEqual($relationship['field_name'], 'field_base_image');
$this->assertEqual($relationship['entity_type'], 'entity_test');
$this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
// Create image field to entity_test_mul.
FieldStorageConfig::create(array(
'entity_type' => 'entity_test_mul',
'field_name' => 'field_data_image',
'type' => 'image',
))->save();
FieldConfig::create(array(
'entity_type' => 'entity_test_mul',
'field_name' => 'field_data_image',
'bundle' => 'entity_test_mul',
))->save();
// Check the generated views data.
$views_data = Views::viewsData()->get('entity_test_mul__field_data_image');
$relationship = $views_data['field_data_image_target_id']['relationship'];
$this->assertEqual($relationship['id'], 'standard');
$this->assertEqual($relationship['base'], 'file_managed');
$this->assertEqual($relationship['base field'], 'fid');
$this->assertEqual($relationship['entity type'], 'file');
// Check the backwards reference.
$views_data = Views::viewsData()->get('file_managed');
$relationship = $views_data['reverse_field_data_image_entity_test_mul']['relationship'];
$this->assertEqual($relationship['id'], 'entity_reverse');
$this->assertEqual($relationship['base'], 'entity_test_mul_property_data');
$this->assertEqual($relationship['base field'], 'id');
$this->assertEqual($relationship['field table'], 'entity_test_mul__field_data_image');
$this->assertEqual($relationship['field field'], 'field_data_image_target_id');
$this->assertEqual($relationship['field_name'], 'field_data_image');
$this->assertEqual($relationship['entity_type'], 'entity_test_mul');
$this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
}
}

View file

@ -0,0 +1,98 @@
<?php
/**
* @file
* Contains \Drupal\image\Tests\Views\RelationshipUserImageDataTest.
*/
namespace Drupal\image\Tests\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Views;
use Drupal\views\Tests\ViewTestData;
/**
* Tests image on user relationship handler.
*
* @group image
*/
class RelationshipUserImageDataTest extends ViewTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('image', 'image_test_views', 'user');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_image_user_image_data');
protected function setUp() {
parent::setUp();
// Create the user profile field and instance.
entity_create('field_storage_config', array(
'entity_type' => 'user',
'field_name' => 'user_picture',
'type' => 'image',
'translatable' => '0',
))->save();
entity_create('field_config', array(
'label' => 'User Picture',
'description' => '',
'field_name' => 'user_picture',
'entity_type' => 'user',
'bundle' => 'user',
'required' => 0,
))->save();
ViewTestData::createTestViews(get_class($this), array('image_test_views'));
}
/**
* Tests using the views image relationship.
*/
public function testViewsHandlerRelationshipUserImageData() {
$file = entity_create('file', array(
'fid' => 2,
'uid' => 2,
'filename' => 'image-test.jpg',
'uri' => "public://image-test.jpg",
'filemime' => 'image/jpeg',
'created' => 1,
'changed' => 1,
'status' => FILE_STATUS_PERMANENT,
));
$file->enforceIsNew();
file_put_contents($file->getFileUri(), file_get_contents('core/modules/simpletest/files/image-1.png'));
$file->save();
$account = $this->drupalCreateUser();
$account->user_picture->target_id = 2;
$account->save();
$view = Views::getView('test_image_user_image_data');
// Tests \Drupal\taxonomy\Plugin\views\relationship\NodeTermData::calculateDependencies().
$expected = [
'module' => [
'file',
'user',
],
];
$this->assertIdentical($expected, $view->calculateDependencies());
$this->executeView($view);
$expected_result = array(
array(
'file_managed_user__user_picture_fid' => '2',
),
);
$column_map = array('file_managed_user__user_picture_fid' => 'file_managed_user__user_picture_fid');
$this->assertIdenticalResultset($view, $expected_result, $column_map);
}
}