3 namespace Drupal\Tests\Core\Image;
5 use Drupal\Core\Image\Image;
6 use Drupal\Core\ImageToolkit\ImageToolkitInterface;
7 use Drupal\Tests\UnitTestCase;
10 * Tests the image class.
12 * @requires extension gd
15 class ImageTest extends UnitTestCase {
27 * @var \Drupal\Core\Image\Image
32 * Mocked image toolkit.
34 * @var \Drupal\Core\ImageToolkit\ImageToolkitInterface
39 * Mocked image toolkit operation.
41 * @var \Drupal\Core\ImageToolkit\ImageToolkitOperationInterface
43 protected $toolkitOperation;
48 protected function setUp() {
49 // Use the Druplicon image.
50 $this->source = __DIR__ . '/../../../../../misc/druplicon.png';
57 * (optional) Array containing methods to be replaced with stubs.
59 * @return \PHPUnit_Framework_MockObject_MockObject
61 protected function getToolkitMock(array $stubs = []) {
62 $mock_builder = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\GDToolkit');
63 $stubs = array_merge(['getPluginId', 'save'], $stubs);
65 ->disableOriginalConstructor()
71 * Mocks a toolkit operation.
73 * @param string $class_name
74 * The name of the GD toolkit operation class to be mocked.
75 * @param ImageToolkitInterface $toolkit
76 * The image toolkit object.
78 * @return \PHPUnit_Framework_MockObject_MockObject
80 protected function getToolkitOperationMock($class_name, ImageToolkitInterface $toolkit) {
81 $mock_builder = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\Operation\gd\\' . $class_name);
82 $logger = $this->getMock('Psr\Log\LoggerInterface');
84 ->setMethods(['execute'])
85 ->setConstructorArgs([[], '', [], $toolkit, $logger])
90 * Get an image with a mocked toolkit, for testing.
92 * @param bool $load_expected
93 * (optional) Whether the load() method is expected to be called. Defaults
96 * (optional) Array containing toolkit methods to be replaced with stubs.
98 * @return \Drupal\Core\Image\Image
101 protected function getTestImage($load_expected = TRUE, array $stubs = []) {
102 if (!$load_expected && !in_array('load', $stubs)) {
103 $stubs = array_merge(['load'], $stubs);
106 $this->toolkit = $this->getToolkitMock($stubs);
108 $this->toolkit->expects($this->any())
109 ->method('getPluginId')
110 ->will($this->returnValue('gd'));
112 if (!$load_expected) {
113 $this->toolkit->expects($this->never())
117 $this->image = new Image($this->toolkit, $this->source);
121 * Get an image with mocked toolkit and operation, for operation testing.
123 * @param string $class_name
124 * The name of the GD toolkit operation class to be mocked.
126 * @return \Drupal\Core\Image\Image
129 protected function getTestImageForOperation($class_name) {
130 $this->toolkit = $this->getToolkitMock(['getToolkitOperation']);
131 $this->toolkitOperation = $this->getToolkitOperationMock($class_name, $this->toolkit);
133 $this->toolkit->expects($this->any())
134 ->method('getPluginId')
135 ->will($this->returnValue('gd'));
137 $this->toolkit->expects($this->any())
138 ->method('getToolkitOperation')
139 ->will($this->returnValue($this->toolkitOperation));
141 $this->image = new Image($this->toolkit, $this->source);
145 * Tests \Drupal\Core\Image\Image::getHeight().
147 public function testGetHeight() {
148 $this->getTestImage(FALSE);
149 $this->assertEquals(100, $this->image->getHeight());
153 * Tests \Drupal\Core\Image\Image::getWidth().
155 public function testGetWidth() {
156 $this->getTestImage(FALSE);
157 $this->assertEquals(88, $this->image->getWidth());
161 * Tests \Drupal\Core\Image\Image::getFileSize
163 public function testGetFileSize() {
164 $this->getTestImage(FALSE);
165 $this->assertEquals(3905, $this->image->getFileSize());
169 * Tests \Drupal\Core\Image\Image::getToolkit()->getType().
171 public function testGetType() {
172 $this->getTestImage(FALSE);
173 $this->assertEquals(IMAGETYPE_PNG, $this->image->getToolkit()->getType());
177 * Tests \Drupal\Core\Image\Image::getMimeType().
179 public function testGetMimeType() {
180 $this->getTestImage(FALSE);
181 $this->assertEquals('image/png', $this->image->getMimeType());
185 * Tests \Drupal\Core\Image\Image::isValid().
187 public function testIsValid() {
188 $this->getTestImage(FALSE);
189 $this->assertTrue($this->image->isValid());
190 $this->assertTrue(is_readable($this->image->getSource()));
194 * Tests \Drupal\Core\Image\Image::getToolkitId().
196 public function testGetToolkitId() {
197 $this->getTestImage(FALSE);
198 $this->assertEquals('gd', $this->image->getToolkitId());
202 * Tests \Drupal\Core\Image\Image::save().
204 public function testSave() {
205 $this->getTestImage();
206 // This will fail if save() method isn't called on the toolkit.
207 $toolkit = $this->getToolkitMock();
208 $toolkit->expects($this->once())
210 ->will($this->returnValue(TRUE));
212 $image = $this->getMock('Drupal\Core\Image\Image', ['chmod'], [$toolkit, $this->image->getSource()]);
213 $image->expects($this->any())
215 ->will($this->returnValue(TRUE));
221 * Tests \Drupal\Core\Image\Image::save().
223 public function testSaveFails() {
224 $this->getTestImage();
225 // This will fail if save() method isn't called on the toolkit.
226 $this->toolkit->expects($this->once())
228 ->will($this->returnValue(FALSE));
230 $this->assertFalse($this->image->save());
234 * Tests \Drupal\Core\Image\Image::save().
236 public function testChmodFails() {
237 $this->getTestImage();
238 // This will fail if save() method isn't called on the toolkit.
239 $toolkit = $this->getToolkitMock();
240 $toolkit->expects($this->once())
242 ->will($this->returnValue(TRUE));
244 $image = $this->getMock('Drupal\Core\Image\Image', ['chmod'], [$toolkit, $this->image->getSource()]);
245 $image->expects($this->any())
247 ->will($this->returnValue(FALSE));
249 $this->assertFalse($image->save());
253 * Tests \Drupal\Core\Image\Image::parseFile().
255 public function testParseFileFails() {
256 $toolkit = $this->getToolkitMock();
257 $image = new Image($toolkit, 'magic-foobars.png');
259 $this->assertFalse($image->isValid());
260 $this->assertFalse($image->save());
264 * Tests \Drupal\Core\Image\Image::scale().
266 public function testScaleWidth() {
267 $this->getTestImageForOperation('Scale');
268 $this->toolkitOperation->expects($this->once())
270 ->will($this->returnArgument(0));
272 $ret = $this->image->scale(44, NULL, FALSE);
273 $this->assertEquals(50, $ret['height']);
277 * Tests \Drupal\Core\Image\Image::scale().
279 public function testScaleHeight() {
280 $this->getTestImageForOperation('Scale');
281 $this->toolkitOperation->expects($this->once())
283 ->will($this->returnArgument(0));
285 $ret = $this->image->scale(NULL, 50, FALSE);
286 $this->assertEquals(44, $ret['width']);
290 * Tests \Drupal\Core\Image\Image::scale().
292 public function testScaleSame() {
293 $this->getTestImageForOperation('Scale');
294 // Dimensions are the same, resize should not be called.
295 $this->toolkitOperation->expects($this->once())
297 ->will($this->returnArgument(0));
299 $ret = $this->image->scale(88, 100, FALSE);
300 $this->assertEquals(88, $ret['width']);
301 $this->assertEquals(100, $ret['height']);
305 * Tests \Drupal\Core\Image\Image::scaleAndCrop().
307 public function testScaleAndCropWidth() {
308 $this->getTestImageForOperation('ScaleAndCrop');
309 $this->toolkitOperation->expects($this->once())
311 ->will($this->returnArgument(0));
313 $ret = $this->image->scaleAndCrop(34, 50, FALSE);
314 $this->assertEquals(5, $ret['x']);
318 * Tests \Drupal\Core\Image\Image::scaleAndCrop().
320 public function testScaleAndCropHeight() {
321 $this->getTestImageForOperation('ScaleAndCrop');
322 $this->toolkitOperation->expects($this->once())
324 ->will($this->returnArgument(0));
326 $ret = $this->image->scaleAndCrop(44, 40);
327 $this->assertEquals(5, $ret['y']);
331 * Tests \Drupal\Core\Image\Image::scaleAndCrop().
333 public function testScaleAndCropFails() {
334 $this->getTestImageForOperation('ScaleAndCrop');
335 $this->toolkitOperation->expects($this->once())
337 ->will($this->returnArgument(0));
339 $ret = $this->image->scaleAndCrop(44, 40);
340 $this->assertEquals(0, $ret['x']);
341 $this->assertEquals(5, $ret['y']);
342 $this->assertEquals(44, $ret['resize']['width']);
343 $this->assertEquals(50, $ret['resize']['height']);
347 * Tests \Drupal\Core\Image\Image::crop().
349 public function testCropWidth() {
350 $this->getTestImageForOperation('Crop');
351 $this->toolkitOperation->expects($this->once())
353 ->will($this->returnArgument(0));
355 // Cropping with width only should preserve the aspect ratio.
356 $ret = $this->image->crop(0, 0, 44);
357 $this->assertEquals(50, $ret['height']);
361 * Tests \Drupal\Core\Image\Image::crop().
363 public function testCropHeight() {
364 $this->getTestImageForOperation('Crop');
365 $this->toolkitOperation->expects($this->once())
367 ->will($this->returnArgument(0));
369 // Cropping with height only should preserve the aspect ratio.
370 $ret = $this->image->crop(0, 0, NULL, 50);
371 $this->assertEquals(44, $ret['width']);
375 * Tests \Drupal\Core\Image\Image::crop().
377 public function testCrop() {
378 $this->getTestImageForOperation('Crop');
379 $this->toolkitOperation->expects($this->once())
381 ->will($this->returnArgument(0));
383 $ret = $this->image->crop(0, 0, 44, 50);
384 $this->assertEquals(44, $ret['width']);
388 * Tests \Drupal\Core\Image\Image::convert().
390 public function testConvert() {
391 $this->getTestImageForOperation('Convert');
392 $this->toolkitOperation->expects($this->once())
394 ->will($this->returnArgument(0));
396 $ret = $this->image->convert('png');
397 $this->assertEquals('png', $ret['extension']);
401 * Tests \Drupal\Core\Image\Image::resize().
403 public function testResize() {
404 $this->getTestImageForOperation('Resize');
405 $this->toolkitOperation->expects($this->once())
407 ->will($this->returnArgument(0));
409 // Resize with integer for width and height.
410 $ret = $this->image->resize(30, 40);
411 $this->assertEquals(30, $ret['width']);
412 $this->assertEquals(40, $ret['height']);
416 * Tests \Drupal\Core\Image\Image::resize().
418 public function testFloatResize() {
419 $this->getTestImageForOperation('Resize');
420 $this->toolkitOperation->expects($this->once())
422 ->will($this->returnArgument(0));
424 // Pass a float for width.
425 $ret = $this->image->resize(30.4, 40);
426 // Ensure that the float was rounded to an integer first.
427 $this->assertEquals(30, $ret['width']);
431 * Tests \Drupal\Core\Image\Image::desaturate().
433 public function testDesaturate() {
434 $this->getTestImageForOperation('Desaturate');
435 $this->toolkitOperation->expects($this->once())
437 ->will($this->returnArgument(0));
439 $this->image->desaturate();
443 * Tests \Drupal\Core\Image\Image::rotate().
445 public function testRotate() {
446 $this->getTestImageForOperation('Rotate');
447 $this->toolkitOperation->expects($this->once())
449 ->will($this->returnArgument(0));
451 $ret = $this->image->rotate(90);
452 $this->assertEquals(90, $ret['degrees']);