1
0
mirror of https://github.com/Intervention/image.git synced 2025-09-09 05:30:40 +02:00

Improve Driver Specializing Process (#1315)

Streamline driver specializing process of analyzers, modifers, encoders and decoders.
This commit is contained in:
Oliver Vogel
2024-03-23 08:08:41 +01:00
committed by GitHub
parent 67be90e570
commit 7f4ff15d51
207 changed files with 1073 additions and 1185 deletions

View File

@@ -21,6 +21,15 @@ abstract class BaseTestCase extends MockeryTestCase
return file_get_contents($this->getTestResourcePath($filename));
}
public function getTestResourcePointer($filename = 'test.jpg')
{
$pointer = fopen('php://temp', 'rw');
fputs($pointer, $this->getTestResourceData($filename));
rewind($pointer);
return $pointer;
}
protected function assertColor($r, $g, $b, $a, ColorInterface $color)
{
$this->assertEquals([$r, $g, $b, $a], $color->toArray());

View File

@@ -13,6 +13,7 @@ use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
use stdClass;
#[CoversClass(\Intervention\Image\Drivers\AbstractDecoder::class)]
final class AbstractDecoderTest extends BaseTestCase
@@ -20,62 +21,63 @@ final class AbstractDecoderTest extends BaseTestCase
public function testHandle(): void
{
$result = Mockery::mock(ColorInterface::class);
$decoder = Mockery::mock(AbstractDecoder::class)->makePartial();
$decoder = Mockery::mock(AbstractDecoder::class);
$decoder->shouldReceive('decode')->with('test input')->andReturn($result);
$decoder->handle('test input');
}
public function testHandleFail(): void
{
$decoder = Mockery::mock(AbstractDecoder::class, [])->makePartial()->shouldAllowMockingProtectedMethods();
$decoder = Mockery::mock(AbstractDecoder::class, []);
$decoder->shouldReceive('decode')->with('test input')->andThrow(DecoderException::class);
$this->expectException(DecoderException::class);
$decoder->handle('test input');
}
public function testHandleFailWithSuccessor(): void
{
$result = Mockery::mock(ColorInterface::class);
$successor = Mockery::mock(AbstractDecoder::class)->makePartial();
$successor = Mockery::mock(AbstractDecoder::class);
$successor->shouldReceive('decode')->with('test input')->andReturn($result);
$decoder = Mockery::mock(
AbstractDecoder::class,
[$successor]
)->makePartial()->shouldAllowMockingProtectedMethods();
);
$decoder->shouldReceive('decode')->with('test input')->andThrow(DecoderException::class);
$decoder->handle('test input');
}
public function testIsGifFormat(): void
{
$decoder = Mockery::mock(AbstractDecoder::class)->makePartial();
$decoder = Mockery::mock(AbstractDecoder::class);
$this->assertFalse($decoder->isGifFormat($this->getTestResourceData('exif.jpg')));
$this->assertTrue($decoder->isGifFormat($this->getTestResourceData('red.gif')));
}
public function testIsFile(): void
{
$decoder = Mockery::mock(AbstractDecoder::class)->makePartial();
$decoder = Mockery::mock(AbstractDecoder::class);
$this->assertTrue($decoder->isFile($this->getTestResourcePath()));
$this->assertFalse($decoder->isFile('non-existent-file'));
$this->assertFalse($decoder->isFile(new stdClass()));
$this->assertFalse($decoder->isFile(str_repeat('o', PHP_MAXPATHLEN + 1)));
$this->assertFalse($decoder->isFile(__DIR__));
}
public function testExtractExifDataFromBinary(): void
{
$decoder = Mockery::mock(AbstractDecoder::class)->makePartial();
$result = $decoder->extractExifData($this->getTestResourceData('exif.jpg'));
$source = $this->getTestResourceData('exif.jpg');
$pointer = $this->getTestResourcePointer('exif.jpg');
$decoder = Mockery::mock(AbstractDecoder::class);
$decoder->shouldReceive('buildFilePointer')->with($source)->andReturn($pointer);
$result = $decoder->extractExifData($source);
$this->assertInstanceOf(CollectionInterface::class, $result);
$this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));
}
public function testExtractExifDataFromPath(): void
{
$decoder = Mockery::mock(AbstractDecoder::class)->makePartial();
$decoder = Mockery::mock(AbstractDecoder::class);
$result = $decoder->extractExifData($this->getTestResourcePath('exif.jpg'));
$this->assertInstanceOf(CollectionInterface::class, $result);
$this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));
@@ -145,5 +147,9 @@ final class AbstractDecoderTest extends BaseTestCase
$this->assertFalse(
$decoder->isValid('foo')
);
$this->assertFalse(
$decoder->isValid(new stdClass())
);
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers;
use Intervention\Image\EncodedImage;
use Intervention\Image\Drivers\AbstractEncoder;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
use PHPUnit\Metadata\CoversClass;
#[CoversClass(\Intervention\Image\Drivers\AbstractEncoder::class)]
final class AbstractEncoderTest extends BaseTestCase
{
public function testEncode(): void
{
$encoder = Mockery::mock(AbstractEncoder::class)->makePartial();
$image = Mockery::mock(ImageInterface::class);
$encoded = Mockery::mock(EncodedImage::class);
$image->shouldReceive('encode')->andReturn($encoded);
$result = $encoder->encode($image);
$this->assertInstanceOf(EncodedImage::class, $result);
}
public function testGetBuffered(): void
{
$encoder = new class () extends AbstractEncoder
{
public function test(callable $callback)
{
return $this->buffered($callback);
}
};
$result = $encoder->test(function () {
echo 'result';
});
$this->assertEquals('result', $result);
}
}

View File

@@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers;
use Intervention\Image\Drivers\AbstractTextModifier;
use Intervention\Image\Geometry\Point;
use PHPUnit\Framework\Attributes\CoversClass;
use Intervention\Image\Tests\BaseTestCase;
use Intervention\Image\Typography\Font;
use Mockery;
#[CoversClass(AbstractTextModifier::class)]
final class AbstractTextModifierTest extends BaseTestCase
{
public function testStrokeOffsets(): void
{
$modifier = Mockery::mock(AbstractTextModifier::class)->makePartial();
$this->assertEquals([
], $modifier->strokeOffsets(
new Font()
));
$this->assertEquals([
new Point(-1, -1),
new Point(-1, 0),
new Point(-1, 1),
new Point(0, -1),
new Point(0, 0),
new Point(0, 1),
new Point(1, -1),
new Point(1, 0),
new Point(1, 1),
], $modifier->strokeOffsets(
(new Font())->setStrokeWidth(1)
));
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers;
use PHPUnit\Framework\Attributes\CoversClass;
use Intervention\Image\Drivers\DriverSpecializedEncoder;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
/**
*
* @internal
*/
#[CoversClass(\Intervention\Image\Drivers\DriverSpecializedEncoder::class)]
final class DriverSpecializedEncoderTest extends BaseTestCase
{
public function testGetBuffered(): void
{
$encoder = Mockery::mock(DriverSpecializedEncoder::class)->makePartial();
$result = $encoder->getBuffered(function () {
echo 'result';
});
$this->assertEquals('result', $result);
}
}

View File

@@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers;
use PHPUnit\Framework\Attributes\CoversClass;
use Intervention\Image\Encoders\JpegEncoder;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Tests\BaseTestCase;
use Intervention\Image\Drivers\DriverSpecialized;
use Mockery;
/**
*
* @internal
*/
#[CoversClass(\Intervention\Image\Drivers\DriverSpecialized::class)]
final class DriverSpecializedTest extends BaseTestCase
{
public function testBuildSpecialized(): void
{
$generic = new JpegEncoder(quality: 10);
$driver = Mockery::mock(DriverInterface::class);
$baseclass = new class () extends DriverSpecialized
{
};
$specialized = forward_static_call(
[$baseclass, 'buildSpecialized'],
$generic,
$driver
);
$this->assertInstanceOf(JpegEncoder::class, $specialized->generic());
$this->assertInstanceOf(DriverInterface::class, $specialized->driver());
$this->assertEquals(10, $specialized->quality);
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Drivers\Gd\Modifiers\TextModifier;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Tests\GdTestCase;
use Intervention\Image\Typography\Font;
#[RequiresPhpExtension('gd')]
#[CoversClass(\Intervention\Image\Modifiers\TextModifier::class)]
#[CoversClass(\Intervention\Image\Drivers\Gd\Modifiers\TextModifier::class)]
final class TextModifierTest extends GdTestCase
{
public function testTextColor(): void
{
$font = (new Font())->setColor('ff0055');
$modifier = new class ('test', new Point(), $font) extends TextModifier
{
public function test()
{
return $this->textColor();
}
};
$modifier->setDriver(new Driver());
$this->assertInstanceOf(ColorInterface::class, $modifier->test());
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\Drivers\Imagick\Modifiers\TextModifier;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ColorInterface;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Tests\ImagickTestCase;
use Intervention\Image\Typography\Font;
#[RequiresPhpExtension('imagick')]
#[CoversClass(\Intervention\Image\Modifiers\TextModifier::class)]
#[CoversClass(\Intervention\Image\Drivers\Imagick\Modifiers\TextModifier::class)]
final class TextModifierTest extends ImagickTestCase
{
public function testTextColor(): void
{
$font = (new Font())->setColor('ff0055');
$modifier = new class ('test', new Point(), $font) extends TextModifier
{
public function test()
{
return $this->textColor();
}
};
$modifier->setDriver(new Driver());
$this->assertInstanceOf(ColorInterface::class, $modifier->test());
}
}

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Analyzers;
namespace Intervention\Image\Tests\Unit\Drivers;
use Intervention\Image\Analyzers\SpecializableAnalyzer;
use Intervention\Image\Drivers\SpecializableAnalyzer;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
@@ -16,7 +16,6 @@ final class SpecializableAnalyzerTest extends BaseTestCase
$analyzer = Mockery::mock(SpecializableAnalyzer::class)->makePartial();
$image = Mockery::mock(ImageInterface::class);
$image->shouldReceive('analyze')->andReturn('test');
$result = $analyzer->analyze($image);
$this->assertEquals('test', $result);
}

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Decoders;
namespace Intervention\Image\Tests\Unit\Drivers;
use Intervention\Image\Decoders\SpecializableDecoder;
use Intervention\Image\Drivers\SpecializableDecoder;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Modifiers;
namespace Intervention\Image\Tests\Unit\Drivers;
use Intervention\Image\Modifiers\SpecializableModifier;
use Intervention\Image\Drivers\SpecializableModifier;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
@@ -16,7 +16,6 @@ final class SpecializableModifierTest extends BaseTestCase
$modifier = Mockery::mock(SpecializableModifier::class)->makePartial();
$image = Mockery::mock(ImageInterface::class);
$image->shouldReceive('modify')->andReturn($image);
$result = $modifier->apply($image);
$this->assertInstanceOf(ImageInterface::class, $result);
}

View File

@@ -15,65 +15,76 @@ use Intervention\Image\Encoders\PngEncoder;
use Intervention\Image\Encoders\TiffEncoder;
use Intervention\Image\Encoders\WebpEncoder;
use Intervention\Image\Exceptions\EncoderException;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
final class FileExtensionEncoderTest extends BaseTestCase
{
private function testEncoder(string $extension): EncoderInterface
{
$encoder = new class () extends FileExtensionEncoder
{
public function test($extension)
{
return $this->encoderByFileExtension($extension);
}
};
return $encoder->test($extension);
}
public function testEncoderByFileExtension(): void
{
$encoder = Mockery::mock(FileExtensionEncoder::class);
$this->assertInstanceOf(
WebpEncoder::class,
$encoder->encoderByFileExtension('webp')
$this->testEncoder('webp')
);
$this->assertInstanceOf(
AvifEncoder::class,
$encoder->encoderByFileExtension('avif')
$this->testEncoder('avif')
);
$this->assertInstanceOf(
JpegEncoder::class,
$encoder->encoderByFileExtension('jpeg')
$this->testEncoder('jpeg')
);
$this->assertInstanceOf(
BmpEncoder::class,
$encoder->encoderByFileExtension('bmp')
$this->testEncoder('bmp')
);
$this->assertInstanceOf(
GifEncoder::class,
$encoder->encoderByFileExtension('gif')
$this->testEncoder('gif')
);
$this->assertInstanceOf(
PngEncoder::class,
$encoder->encoderByFileExtension('png')
$this->testEncoder('png')
);
$this->assertInstanceOf(
TiffEncoder::class,
$encoder->encoderByFileExtension('tiff')
$this->testEncoder('tiff')
);
$this->assertInstanceOf(
Jpeg2000Encoder::class,
$encoder->encoderByFileExtension('jp2')
$this->testEncoder('jp2')
);
$this->assertInstanceOf(
HeicEncoder::class,
$encoder->encoderByFileExtension('heic')
$this->testEncoder('heic')
);
}
public function testEncoderByFileExtensionUnknown(): void
{
$encoder = Mockery::mock(FileExtensionEncoder::class);
$this->expectException(EncoderException::class);
$encoder->encoderByFileExtension('test');
$this->testEncoder('test');
}
}

View File

@@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Encoders;
use Intervention\Image\EncodedImage;
use Intervention\Image\Encoders\SpecializableEncoder;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Tests\BaseTestCase;
use Mockery;
final class SpecializableEncoderTest extends BaseTestCase
{
public function testConstructorDefault(): void
{
$encoder = new class () extends SpecializableEncoder
{
};
$this->assertEquals(75, $encoder->quality);
}
public function testConstructorList(): void
{
$encoder = new class (1) extends SpecializableEncoder
{
};
$this->assertEquals(1, $encoder->quality);
}
public function testConstructorNamed(): void
{
$encoder = new class (quality: 1) extends SpecializableEncoder
{
};
$this->assertEquals(1, $encoder->quality);
}
public function testEncode(): void
{
$encoder = Mockery::mock(SpecializableEncoder::class)->makePartial();
$image = Mockery::mock(ImageInterface::class);
$encoded = Mockery::mock(EncodedImage::class);
$image->shouldReceive('encode')->andReturn($encoded);
$result = $encoder->encode($image);
$this->assertInstanceOf(EncodedImage::class, $result);
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Modifiers;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Modifiers\TextModifier;
use Intervention\Image\Tests\BaseTestCase;
use Intervention\Image\Typography\Font;
final class TextModifierTest extends BaseTestCase
{
public function testStrokeOffsets(): void
{
$modifier = new class ('test', new Point(), new Font()) extends TextModifier
{
public function testStrokeOffsets($font)
{
return $this->strokeOffsets($font);
}
};
$this->assertEquals([], $modifier->testStrokeOffsets(new Font()));
$this->assertEquals([
new Point(-1, -1),
new Point(-1, 0),
new Point(-1, 1),
new Point(0, -1),
new Point(0, 0),
new Point(0, 1),
new Point(1, -1),
new Point(1, 0),
new Point(1, 1),
], $modifier->testStrokeOffsets((new Font())->setStrokeWidth(1)));
}
}