diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 67fc091..09e51f1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,6 +36,11 @@ jobs:
extensions: iconv, imagick, gd
coverage: xdebug
+ - name: Setup Node
+ uses: actions/setup-node@v6
+ with:
+ node-version: 24
+
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
@@ -47,9 +52,12 @@ jobs:
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- - name: Install dependencies
+ - name: Install PHP dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
+ - name: Install Node dependencies
+ run: npm install
+
- name: Test with phpunit
run: vendor/bin/phpunit --coverage-clover clover.xml
@@ -58,7 +66,7 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./clover.xml
-
+
release:
needs: [lint, test]
runs-on: ubuntu-latest
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 870931b..f7071a6 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -24,7 +24,7 @@ jobs:
strategy:
matrix:
operating-system: [ubuntu-latest]
- php-versions: ['8.1', '8.2', '8.3']
+ php-versions: ['8.1', '8.2', '8.3', '8.4']
runs-on: ${{ matrix.operating-system }}
steps:
- uses: actions/checkout@v4
@@ -36,6 +36,11 @@ jobs:
extensions: iconv, imagick
coverage: xdebug
+ - name: Setup Node
+ uses: actions/setup-node@v6
+ with:
+ node-version: 24
+
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
@@ -47,9 +52,12 @@ jobs:
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- - name: Install dependencies
+ - name: Install PHP dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
+ - name: Install Node dependencies
+ run: npm install
+
- name: Test with phpunit
run: vendor/bin/phpunit --coverage-clover clover.xml
diff --git a/.gitignore b/.gitignore
index 9d5cbb4..3edc4a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/composer.lock
/vendor
+/node_modules
/.phpunit.result.cache
/.phpunit.cache
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 4bafbf4..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM php:8.1-cli
-
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
-RUN apt-get update && apt-get install -y libmagickwand-dev libzip-dev zip --no-install-recommends && rm -rf /var/lib/apt/lists/*
-RUN pecl install imagick && docker-php-ext-enable imagick && docker-php-ext-install zip
-RUN alias composer='php /usr/bin/composer'
-
-WORKDIR /app
diff --git a/LICENSE b/LICENSE
index d45a356..aa22018 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2017, Ben Scholzen 'DASPRiD'
+Copyright (c) 2017-present, Ben Scholzen 'DASPRiD'
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index e429889..8291c26 100644
--- a/README.md
+++ b/README.md
@@ -55,3 +55,8 @@ $renderer = new GDLibRenderer(400);
$writer = new Writer($renderer);
$writer->writeFile('Hello World!', 'qrcode.png');
```
+
+## Development
+
+To run unit tests, you need to have [Node.js](https://nodejs.org/en) and the pixelmatch library installed. Running
+`npm install` will install this for you.
diff --git a/composer.json b/composer.json
index d086357..37e8c75 100644
--- a/composer.json
+++ b/composer.json
@@ -32,6 +32,7 @@
"require-dev": {
"phpunit/phpunit": "^10.5.11 || ^11.0.4",
"spatie/phpunit-snapshot-assertions": "^5.1.5",
+ "spatie/pixelmatch-php": "^1.2.0",
"squizlabs/php_codesniffer": "^3.9",
"phly/keep-a-changelog": "^2.12"
},
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..810fd07
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,34 @@
+{
+ "name": "baconqrcode",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "baconqrcode",
+ "dependencies": {
+ "pixelmatch": "^7.1.0"
+ }
+ },
+ "node_modules/pixelmatch": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz",
+ "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==",
+ "license": "ISC",
+ "dependencies": {
+ "pngjs": "^7.0.0"
+ },
+ "bin": {
+ "pixelmatch": "bin/pixelmatch"
+ }
+ },
+ "node_modules/pngjs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
+ "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.19.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1bc4886
--- /dev/null
+++ b/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "baconqrcode",
+ "private": true,
+ "dependencies": {
+ "pixelmatch": "^7.1.0"
+ }
+}
diff --git a/test/Integration/GDLibRenderingTest.php b/test/Integration/GDLibRenderingTest.php
index 47b1e28..8e78e6d 100644
--- a/test/Integration/GDLibRenderingTest.php
+++ b/test/Integration/GDLibRenderingTest.php
@@ -5,22 +5,14 @@
namespace BaconQrCodeTest\Integration;
use BaconQrCode\Exception\InvalidArgumentException;
-use BaconQrCode\Exception\RuntimeException;
use BaconQrCode\Renderer\Color\Alpha;
use BaconQrCode\Renderer\Color\Rgb;
-use BaconQrCode\Renderer\Eye\EyeInterface;
-use BaconQrCode\Renderer\Eye\SimpleCircleEye;
-use BaconQrCode\Renderer\Eye\SquareEye;
use BaconQrCode\Renderer\GDLibRenderer;
-use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\Image\GDImageBackEnd;
-use BaconQrCode\Renderer\Module\DotsModule;
-use BaconQrCode\Renderer\Module\RoundnessModule;
use BaconQrCode\Renderer\RendererStyle\EyeFill;
use BaconQrCode\Renderer\RendererStyle\Fill;
use BaconQrCode\Renderer\RendererStyle\Gradient;
use BaconQrCode\Renderer\RendererStyle\GradientType;
-use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
@@ -40,7 +32,7 @@ public function testGenericQrCode(): void
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer->writeFile('Hello World!', $tempName);
- $this->assertMatchesFileSnapshot($tempName);
+ $this->assertMatchesImageSnapshot($tempName);
unlink($tempName);
}
@@ -64,7 +56,7 @@ public function testDifferentColorsQrCode(): void
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer->writeFile('Hello World!', $tempName);
- $this->assertMatchesFileSnapshot($tempName);
+ $this->assertMatchesImageSnapshot($tempName);
unlink($tempName);
}
diff --git a/test/Integration/ImagickRenderingTest.php b/test/Integration/ImagickRenderingTest.php
index a523839..f51e7eb 100644
--- a/test/Integration/ImagickRenderingTest.php
+++ b/test/Integration/ImagickRenderingTest.php
@@ -36,7 +36,7 @@ public function testGenericQrCode() : void
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer->writeFile('Hello World!', $tempName);
- $this->assertMatchesFileSnapshot($tempName);
+ $this->assertMatchesImageSnapshot($tempName);
unlink($tempName);
}
@@ -63,10 +63,11 @@ public function testIssue79() : void
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer->writeFile('https://apiroad.net/very-long-url', $tempName);
- $this->assertMatchesFileSnapshot($tempName);
+ $this->assertMatchesImageSnapshot($tempName);
unlink($tempName);
}
+ #[RequiresPhpExtension('imagick')]
public function testIssue105() : void
{
$squareModule = SquareModule::instance();
@@ -86,7 +87,7 @@ public function testIssue105() : void
$tempName1 = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer1->writeFile('rotation without eye color', $tempName1);
- $this->assertMatchesFileSnapshot($tempName1);
+ $this->assertMatchesImageSnapshot($tempName1);
unlink($tempName1);
$eyeFill = new EyeFill(new Rgb(255, 0, 0), new Rgb(0, 255, 0));
@@ -105,7 +106,7 @@ public function testIssue105() : void
$tempName2 = tempnam(sys_get_temp_dir(), 'test') . '.png';
$writer2->writeFile('rotation with eye color', $tempName2);
- $this->assertMatchesFileSnapshot($tempName2);
+ $this->assertMatchesImageSnapshot($tempName2);
unlink($tempName2);
}
}
diff --git a/test/Integration/SVGRenderingTest.php b/test/Integration/SVGRenderingTest.php
index 2eb71d9..1655950 100644
--- a/test/Integration/SVGRenderingTest.php
+++ b/test/Integration/SVGRenderingTest.php
@@ -15,10 +15,13 @@
use BaconQrCode\Writer;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
+use Spatie\Snapshots\MatchesSnapshots;
#[Group('integration')]
final class SVGRenderingTest extends TestCase
{
+ use MatchesSnapshots;
+
public function testGenericQrCode(): void
{
$renderer = new ImageRenderer(
@@ -26,18 +29,15 @@ public function testGenericQrCode(): void
new SvgImageBackEnd()
);
$writer = new Writer($renderer);
+ $svg = $writer->writeString('Hello World!');
- $svgCode = $writer->writeString('Hello World!');
- $expected = file_get_contents(__DIR__.'/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg');
-
- $this->assertEquals($expected, $svgCode);
+ $this->assertMatchesXmlSnapshot($svg);
}
- // SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients_horizontal
- //SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients_vertical
public function testQrWithGradientGeneratesDifferentIdsForDifferentGradients()
{
$types = ['HORIZONTAL', 'VERTICAL'];
+
foreach ($types as $type) {
$gradient = new Gradient(
new Rgb(0, 0, 0),
@@ -58,13 +58,9 @@ public function testQrWithGradientGeneratesDifferentIdsForDifferentGradients()
new SvgImageBackEnd()
);
$writer = new Writer($renderer);
- $qr = $writer->writeString('Hello World!');
- $expectedFile = __DIR__ . '/__snapshots__/files/';
- $expectedFile .= 'SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__';
- $expectedFile .= strtolower($type) . '.svg';
- $expected = file_get_contents($expectedFile);
+ $svg = $writer->writeString('Hello World!');
- $this->assertEquals($expected, $qr);
+ $this->assertMatchesXmlSnapshot($svg);
}
}
}
diff --git a/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png b/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png
new file mode 100644
index 0000000..c2d6ae6
Binary files /dev/null and b/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png differ
diff --git a/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png b/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png
new file mode 100644
index 0000000..4c1faa8
Binary files /dev/null and b/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png differ
diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testGenericQrCode__1.png
similarity index 100%
rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png
rename to test/Integration/__snapshots__/ImagickRenderingTest__testGenericQrCode__1.png
diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__1.png
similarity index 100%
rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__1.png
rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__1.png
diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__2.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__2.png
similarity index 100%
rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__2.png
rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__2.png
diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue79__1.png
similarity index 100%
rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png
rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue79__1.png
diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml b/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml
new file mode 100644
index 0000000..b602bbb
--- /dev/null
+++ b/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml
new file mode 100644
index 0000000..5ebaedd
--- /dev/null
+++ b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml
new file mode 100644
index 0000000..466151f
--- /dev/null
+++ b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg
deleted file mode 100644
index 8c8607e..0000000
--- a/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg
deleted file mode 100644
index aa79f5d..0000000
--- a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg
deleted file mode 100644
index 60c25da..0000000
--- a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-
-