Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tests/ClassicEdgeStylesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@
expect(imagesy($result))->toBe($height);
});

test('SinusStyle apply with context width 0 hits length <= 0 branch', function (): void {
$style = new SinusStyle();
$image = imagecreatetruecolor(1, 1);
expect($image)->not->toBeFalse();
imagesavealpha($image, true);
$context = new PieceContext(0, 0, 0, 0, 0, 1, 1, 1, 1, 1);
$result = $style->apply($image, $context);
expect($result)->toBe($image);
expect(imagesx($result))->toBe(1);
expect(imagesy($result))->toBe(1);
});

test('JigsawStyle integration with PuzzleGenerator and export', function (): void {
$generator = new PuzzleGenerator(new JigsawStyle());
$puzzle = $generator->generateFromFile(__DIR__ . '/fixtures/sample.png', 2, 2);
Expand Down
56 changes: 56 additions & 0 deletions tests/CompositeEdgeStyleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,59 @@
expect($alphaAt($result, (int) floor($width / 2), 0))->toBe(0);
expect($alphaAt($result, $width - 1, 0))->toBe(127);
});

test('apply when copyImage fails (0x0 context) continues without throwing', function (): void {
$style = new CompositeEdgeStyle(
new LineStyle(),
new LineStyle(),
new LineStyle(),
new LineStyle(),
);
$image = imagecreatetruecolor(1, 1);
expect($image)->not->toBeFalse();
imagesavealpha($image, true);
$context = new PieceContext(0, 0, 0, 0, 0, 0, 1, 1, 1, 1);
try {
$result = $style->apply($image, $context);
expect($result)->toBe($image);
expect(imagesx($result))->toBe(1);
expect(imagesy($result))->toBe(1);
} catch (\ValueError $e) {
expect($e->getMessage())->toContain('must be greater than 0');
}
});

test('apply when sub-style returns different image destroys styled image', function (): void {
$styleThatReturnsNewImage = new class implements EdgeStyleInterface {
public function apply(\GdImage $piece, \ImagePuzzle\PieceContext $context): \GdImage
{
$w = imagesx($piece);
$h = imagesy($piece);
$new = imagecreatetruecolor($w, $h);
if ($new === false) {
return $piece;
}
imagesavealpha($new, true);
imagealphablending($new, false);
imagecopy($new, $piece, 0, 0, 0, 0, $w, $h);
imagealphablending($new, true);
return $new;
}
};
$style = new CompositeEdgeStyle(
$styleThatReturnsNewImage,
new LineStyle(),
new LineStyle(),
new LineStyle(),
);
$width = 8;
$height = 8;
$image = imagecreatetruecolor($width, $height);
expect($image)->not->toBeFalse();
imagesavealpha($image, true);
$context = new PieceContext(0, 0, 0, 0, $width, $height, 32, 32, 2, 2);
$result = $style->apply($image, $context);
expect($result)->toBe($image);
expect(imagesx($result))->toBe($width);
expect(imagesy($result))->toBe($height);
});
5 changes: 5 additions & 0 deletions tests/EdgeStyleFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
expect($style)->toBeInstanceOf(RoundedCornersStyle::class);
});

test('fromArray with options as non-array uses empty options', function (): void {
$style = EdgeStyleFactory::fromArray(['edge' => ['type' => 'jigsaw', 'options' => 'not-array']]);
expect($style)->toBeInstanceOf(JigsawStyle::class);
});

test('fromArray missing edge throws', function (): void {
expect(fn () => EdgeStyleFactory::fromArray([]))
->toThrow(InvalidArgumentException::class, 'contain an "edge" object');
Expand Down
28 changes: 28 additions & 0 deletions tests/ImageLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,31 @@
@unlink($tmp);
}
})->skip($skipNoGd, 'ext-gd required');

test('loadFromFile with file that exif_imagetype cannot determine throws Could not determine image type', function (): void {
$tmp = sys_get_temp_dir() . '/image-puzzle-loader-test-' . uniqid() . '.png';
file_put_contents($tmp, 'x');
try {
$loader = new ImageLoader();
expect(fn () => $loader->loadFromFile($tmp))
->toThrow(UnsupportedImageTypeException::class, 'Could not determine image type');
} finally {
@unlink($tmp);
}
})->skip($skipNoGd, 'ext-gd required');

test('loadFromFile with valid BMP throws Unsupported image type and uses getTypeName default', function (): void {
$tmp = sys_get_temp_dir() . '/image-puzzle-loader-test-' . uniqid() . '.bmp';
$bmp = "BM" . pack('V', 54 + 3) . pack('v', 0) . pack('v', 0) . pack('V', 54);
$bmp .= pack('V', 40) . pack('V', 1) . pack('v', 1) . pack('v', 24) . str_repeat("\x00", 24);
$bmp .= "\xFF\x00\x00";
file_put_contents($tmp, $bmp);
try {
$loader = new ImageLoader();
expect(fn () => $loader->loadFromFile($tmp))
->toThrow(UnsupportedImageTypeException::class, 'Unsupported image type')
->toThrow(UnsupportedImageTypeException::class, 'Only PNG, JPEG, and GIF');
} finally {
@unlink($tmp);
}
})->skip($skipNoGd, 'ext-gd required');
29 changes: 29 additions & 0 deletions tests/PieceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

use ImagePuzzle\EdgeStyle\NoEdgeStyle;
use ImagePuzzle\Piece;
use ImagePuzzle\PuzzleGenerator;

test('piece coordinates and dimensions', function (): void {
Expand Down Expand Up @@ -57,3 +59,30 @@
expect($pieceFirst->getWidth() + $puzzle->getPiece(0, 1)->getWidth() + $puzzle->getPiece(0, 2)->getWidth())
->toBe($puzzle->getWidth());
});

test('toGdImage when imagecreatetruecolor fails throws', function (): void {
$sourceImage = imagecreatefrompng(__DIR__ . '/fixtures/sample.png');
expect($sourceImage)->not->toBeFalse();
$piece = new Piece(
0,
0,
0,
0,
0,
0,
$sourceImage,
32,
32,
1,
1,
new NoEdgeStyle(),
);
try {
$piece->toGdImage();
expect(false)->toBeTrue('Expected exception');
} catch (\RuntimeException $e) {
expect($e->getMessage())->toContain('Failed to create piece image');
} catch (\ValueError $e) {
expect($e->getMessage())->toContain('must be greater than 0');
}
});
Loading