image.test

  1. 7.x drupal/modules/simpletest/tests/image.test
  2. 7.x drupal/modules/image/image.test

Tests for image.module.

File

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

Classes

Namesort descending Description
ImageAdminStylesUnitTest Tests creation, deletion, and editing of image styles and effects.
ImageDimensionsScaleTestCase Tests image_dimensions_scale().
ImageDimensionsTestCase Tests that images have correct dimensions when styled.
ImageEffectsUnitTest Use the image_test.module's mock toolkit to ensure that the effects are properly passing parameters to the image toolkit.
ImageFieldDefaultImagesTestCase Tests default image settings.
ImageFieldDisplayTestCase Test class to check that formatters and display settings are working.
ImageFieldTestCase This class provides methods specifically for testing Image's field handling.
ImageFieldValidateTestCase Test class to check for various validations.
ImageStylesPathAndUrlTestCase Tests the functions for generating paths and URLs for image styles.
ImageThemeFunctionWebTestCase Tests image theme functions.