Version 1
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Image / ImageTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Image;
4
5 use Drupal\Core\Image\Image;
6 use Drupal\Core\ImageToolkit\ImageToolkitInterface;
7 use Drupal\Tests\UnitTestCase;
8
9 /**
10  * Tests the image class.
11  *
12  * @requires extension gd
13  * @group Image
14  */
15 class ImageTest extends UnitTestCase {
16
17   /**
18    * Image source path.
19    *
20    * @var string
21    */
22   protected $source;
23
24   /**
25    * Image object.
26    *
27    * @var \Drupal\Core\Image\Image
28    */
29   protected $image;
30
31   /**
32    * Mocked image toolkit.
33    *
34    * @var \Drupal\Core\ImageToolkit\ImageToolkitInterface
35    */
36   protected $toolkit;
37
38   /**
39    * Mocked image toolkit operation.
40    *
41    * @var \Drupal\Core\ImageToolkit\ImageToolkitOperationInterface
42    */
43   protected $toolkitOperation;
44
45   /**
46    * {@inheritdoc}
47    */
48   protected function setUp() {
49     // Use the Druplicon image.
50     $this->source = __DIR__ . '/../../../../../misc/druplicon.png';
51   }
52
53   /**
54    * Mocks a toolkit.
55    *
56    * @param array $stubs
57    *   (optional) Array containing methods to be replaced with stubs.
58    *
59    * @return \PHPUnit_Framework_MockObject_MockObject
60    */
61   protected function getToolkitMock(array $stubs = []) {
62     $mock_builder = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\GDToolkit');
63     $stubs = array_merge(['getPluginId', 'save'], $stubs);
64     return $mock_builder
65       ->disableOriginalConstructor()
66       ->setMethods($stubs)
67       ->getMock();
68   }
69
70   /**
71    * Mocks a toolkit operation.
72    *
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.
77    *
78    * @return \PHPUnit_Framework_MockObject_MockObject
79    */
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');
83     return $mock_builder
84       ->setMethods(['execute'])
85       ->setConstructorArgs([[], '', [], $toolkit, $logger])
86       ->getMock();
87   }
88
89   /**
90    * Get an image with a mocked toolkit, for testing.
91    *
92    * @param bool $load_expected
93    *   (optional) Whether the load() method is expected to be called. Defaults
94    *   to TRUE.
95    * @param array $stubs
96    *   (optional) Array containing toolkit methods to be replaced with stubs.
97    *
98    * @return \Drupal\Core\Image\Image
99    *   An image object.
100    */
101   protected function getTestImage($load_expected = TRUE, array $stubs = []) {
102     if (!$load_expected && !in_array('load', $stubs)) {
103       $stubs = array_merge(['load'], $stubs);
104     }
105
106     $this->toolkit = $this->getToolkitMock($stubs);
107
108     $this->toolkit->expects($this->any())
109       ->method('getPluginId')
110       ->will($this->returnValue('gd'));
111
112     if (!$load_expected) {
113       $this->toolkit->expects($this->never())
114         ->method('load');
115     }
116
117     $this->image = new Image($this->toolkit, $this->source);
118   }
119
120   /**
121    * Get an image with mocked toolkit and operation, for operation testing.
122    *
123    * @param string $class_name
124    *   The name of the GD toolkit operation class to be mocked.
125    *
126    * @return \Drupal\Core\Image\Image
127    *   An image object.
128    */
129   protected function getTestImageForOperation($class_name) {
130     $this->toolkit = $this->getToolkitMock(['getToolkitOperation']);
131     $this->toolkitOperation = $this->getToolkitOperationMock($class_name, $this->toolkit);
132
133     $this->toolkit->expects($this->any())
134       ->method('getPluginId')
135       ->will($this->returnValue('gd'));
136
137     $this->toolkit->expects($this->any())
138       ->method('getToolkitOperation')
139       ->will($this->returnValue($this->toolkitOperation));
140
141     $this->image = new Image($this->toolkit, $this->source);
142   }
143
144   /**
145    * Tests \Drupal\Core\Image\Image::getHeight().
146    */
147   public function testGetHeight() {
148     $this->getTestImage(FALSE);
149     $this->assertEquals(100, $this->image->getHeight());
150   }
151
152   /**
153    * Tests \Drupal\Core\Image\Image::getWidth().
154    */
155   public function testGetWidth() {
156     $this->getTestImage(FALSE);
157     $this->assertEquals(88, $this->image->getWidth());
158   }
159
160   /**
161    * Tests \Drupal\Core\Image\Image::getFileSize
162    */
163   public function testGetFileSize() {
164     $this->getTestImage(FALSE);
165     $this->assertEquals(3905, $this->image->getFileSize());
166   }
167
168   /**
169    * Tests \Drupal\Core\Image\Image::getToolkit()->getType().
170    */
171   public function testGetType() {
172     $this->getTestImage(FALSE);
173     $this->assertEquals(IMAGETYPE_PNG, $this->image->getToolkit()->getType());
174   }
175
176   /**
177    * Tests \Drupal\Core\Image\Image::getMimeType().
178    */
179   public function testGetMimeType() {
180     $this->getTestImage(FALSE);
181     $this->assertEquals('image/png', $this->image->getMimeType());
182   }
183
184   /**
185    * Tests \Drupal\Core\Image\Image::isValid().
186    */
187   public function testIsValid() {
188     $this->getTestImage(FALSE);
189     $this->assertTrue($this->image->isValid());
190     $this->assertTrue(is_readable($this->image->getSource()));
191   }
192
193   /**
194    * Tests \Drupal\Core\Image\Image::getToolkitId().
195    */
196   public function testGetToolkitId() {
197     $this->getTestImage(FALSE);
198     $this->assertEquals('gd', $this->image->getToolkitId());
199   }
200
201   /**
202    * Tests \Drupal\Core\Image\Image::save().
203    */
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())
209       ->method('save')
210       ->will($this->returnValue(TRUE));
211
212     $image = $this->getMock('Drupal\Core\Image\Image', ['chmod'], [$toolkit, $this->image->getSource()]);
213     $image->expects($this->any())
214       ->method('chmod')
215       ->will($this->returnValue(TRUE));
216
217     $image->save();
218   }
219
220   /**
221    * Tests \Drupal\Core\Image\Image::save().
222    */
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())
227       ->method('save')
228       ->will($this->returnValue(FALSE));
229
230     $this->assertFalse($this->image->save());
231   }
232
233   /**
234    * Tests \Drupal\Core\Image\Image::save().
235    */
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())
241       ->method('save')
242       ->will($this->returnValue(TRUE));
243
244     $image = $this->getMock('Drupal\Core\Image\Image', ['chmod'], [$toolkit, $this->image->getSource()]);
245     $image->expects($this->any())
246       ->method('chmod')
247       ->will($this->returnValue(FALSE));
248
249     $this->assertFalse($image->save());
250   }
251
252   /**
253    * Tests \Drupal\Core\Image\Image::parseFile().
254    */
255   public function testParseFileFails() {
256     $toolkit = $this->getToolkitMock();
257     $image = new Image($toolkit, 'magic-foobars.png');
258
259     $this->assertFalse($image->isValid());
260     $this->assertFalse($image->save());
261   }
262
263   /**
264    * Tests \Drupal\Core\Image\Image::scale().
265    */
266   public function testScaleWidth() {
267     $this->getTestImageForOperation('Scale');
268     $this->toolkitOperation->expects($this->once())
269       ->method('execute')
270       ->will($this->returnArgument(0));
271
272     $ret = $this->image->scale(44, NULL, FALSE);
273     $this->assertEquals(50, $ret['height']);
274   }
275
276   /**
277    * Tests \Drupal\Core\Image\Image::scale().
278    */
279   public function testScaleHeight() {
280     $this->getTestImageForOperation('Scale');
281     $this->toolkitOperation->expects($this->once())
282       ->method('execute')
283       ->will($this->returnArgument(0));
284
285     $ret = $this->image->scale(NULL, 50, FALSE);
286     $this->assertEquals(44, $ret['width']);
287   }
288
289   /**
290    * Tests \Drupal\Core\Image\Image::scale().
291    */
292   public function testScaleSame() {
293     $this->getTestImageForOperation('Scale');
294     // Dimensions are the same, resize should not be called.
295     $this->toolkitOperation->expects($this->once())
296       ->method('execute')
297       ->will($this->returnArgument(0));
298
299     $ret = $this->image->scale(88, 100, FALSE);
300     $this->assertEquals(88, $ret['width']);
301     $this->assertEquals(100, $ret['height']);
302   }
303
304   /**
305    * Tests \Drupal\Core\Image\Image::scaleAndCrop().
306    */
307   public function testScaleAndCropWidth() {
308     $this->getTestImageForOperation('ScaleAndCrop');
309     $this->toolkitOperation->expects($this->once())
310       ->method('execute')
311       ->will($this->returnArgument(0));
312
313     $ret = $this->image->scaleAndCrop(34, 50, FALSE);
314     $this->assertEquals(5, $ret['x']);
315   }
316
317   /**
318    * Tests \Drupal\Core\Image\Image::scaleAndCrop().
319    */
320   public function testScaleAndCropHeight() {
321     $this->getTestImageForOperation('ScaleAndCrop');
322     $this->toolkitOperation->expects($this->once())
323       ->method('execute')
324       ->will($this->returnArgument(0));
325
326     $ret = $this->image->scaleAndCrop(44, 40);
327     $this->assertEquals(5, $ret['y']);
328   }
329
330   /**
331    * Tests \Drupal\Core\Image\Image::scaleAndCrop().
332    */
333   public function testScaleAndCropFails() {
334     $this->getTestImageForOperation('ScaleAndCrop');
335     $this->toolkitOperation->expects($this->once())
336       ->method('execute')
337       ->will($this->returnArgument(0));
338
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']);
344   }
345
346   /**
347    * Tests \Drupal\Core\Image\Image::crop().
348    */
349   public function testCropWidth() {
350     $this->getTestImageForOperation('Crop');
351     $this->toolkitOperation->expects($this->once())
352       ->method('execute')
353       ->will($this->returnArgument(0));
354
355     // Cropping with width only should preserve the aspect ratio.
356     $ret = $this->image->crop(0, 0, 44);
357     $this->assertEquals(50, $ret['height']);
358   }
359
360   /**
361    * Tests \Drupal\Core\Image\Image::crop().
362    */
363   public function testCropHeight() {
364     $this->getTestImageForOperation('Crop');
365     $this->toolkitOperation->expects($this->once())
366       ->method('execute')
367       ->will($this->returnArgument(0));
368
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']);
372   }
373
374   /**
375    * Tests \Drupal\Core\Image\Image::crop().
376    */
377   public function testCrop() {
378     $this->getTestImageForOperation('Crop');
379     $this->toolkitOperation->expects($this->once())
380       ->method('execute')
381       ->will($this->returnArgument(0));
382
383     $ret = $this->image->crop(0, 0, 44, 50);
384     $this->assertEquals(44, $ret['width']);
385   }
386
387   /**
388    * Tests \Drupal\Core\Image\Image::convert().
389    */
390   public function testConvert() {
391     $this->getTestImageForOperation('Convert');
392     $this->toolkitOperation->expects($this->once())
393       ->method('execute')
394       ->will($this->returnArgument(0));
395
396     $ret = $this->image->convert('png');
397     $this->assertEquals('png', $ret['extension']);
398   }
399
400   /**
401    * Tests \Drupal\Core\Image\Image::resize().
402    */
403   public function testResize() {
404     $this->getTestImageForOperation('Resize');
405     $this->toolkitOperation->expects($this->once())
406       ->method('execute')
407       ->will($this->returnArgument(0));
408
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']);
413   }
414
415   /**
416    * Tests \Drupal\Core\Image\Image::resize().
417    */
418   public function testFloatResize() {
419     $this->getTestImageForOperation('Resize');
420     $this->toolkitOperation->expects($this->once())
421       ->method('execute')
422       ->will($this->returnArgument(0));
423
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']);
428   }
429
430   /**
431    * Tests \Drupal\Core\Image\Image::desaturate().
432    */
433   public function testDesaturate() {
434     $this->getTestImageForOperation('Desaturate');
435     $this->toolkitOperation->expects($this->once())
436       ->method('execute')
437       ->will($this->returnArgument(0));
438
439     $this->image->desaturate();
440   }
441
442   /**
443    * Tests \Drupal\Core\Image\Image::rotate().
444    */
445   public function testRotate() {
446     $this->getTestImageForOperation('Rotate');
447     $this->toolkitOperation->expects($this->once())
448       ->method('execute')
449       ->will($this->returnArgument(0));
450
451     $ret = $this->image->rotate(90);
452     $this->assertEquals(90, $ret['degrees']);
453   }
454
455 }