From 27d84779b0b94cffe5ab2ca7c8e85dcdd3502f8e Mon Sep 17 00:00:00 2001 From: jmleroux Date: Sat, 11 Oct 2025 15:00:39 +0200 Subject: [PATCH 01/12] feat: Introduce PhpUnit --- composer.json | 1 + phpunit.xml | 20 +++++ tests/BadgeTest.php | 73 ++++++++++++++++++ tests/Fixtures/flat-square.svg | 20 +++++ tests/Fixtures/flat.svg | 20 +++++ tests/Fixtures/invalid_template/plastic.svg | 13 ++++ tests/Fixtures/license.svg | 14 ++++ tests/Fixtures/xml_template/plastic.svg | 26 +++++++ tests/PoserTest.php | 83 +++++++++++++++++++++ tests/Render/SvgFlatRenderTest.php | 52 +++++++++++++ tests/Render/SvgFlatSquareRenderTest.php | 52 +++++++++++++ tests/Render/SvgPlasticRenderTest.php | 66 ++++++++++++++++ 12 files changed, 440 insertions(+) create mode 100644 phpunit.xml create mode 100644 tests/BadgeTest.php create mode 100644 tests/Fixtures/flat-square.svg create mode 100644 tests/Fixtures/flat.svg create mode 100644 tests/Fixtures/invalid_template/plastic.svg create mode 100644 tests/Fixtures/license.svg create mode 100644 tests/Fixtures/xml_template/plastic.svg create mode 100644 tests/PoserTest.php create mode 100644 tests/Render/SvgFlatRenderTest.php create mode 100644 tests/Render/SvgFlatSquareRenderTest.php create mode 100644 tests/Render/SvgPlasticRenderTest.php diff --git a/composer.json b/composer.json index 92cf8ace..80e0da8c 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "friendsofphp/php-cs-fixer": "^3.41", "moave/phpspec-data-provider-extension": "dev-master", "phpspec/phpspec": "^7.4 || ^8.0", + "phpunit/phpunit": "@stable", "vimeo/psalm": "^4.30" }, "config": { diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..a1992819 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,20 @@ + + + + + tests + + + + + src + + + diff --git a/tests/BadgeTest.php b/tests/BadgeTest.php new file mode 100644 index 00000000..7f022fbd --- /dev/null +++ b/tests/BadgeTest.php @@ -0,0 +1,73 @@ +assertInstanceOf(Badge::class, $badge); + } + + public function testShouldBeConstructedByFromURIFactoryMethod(): void + { + $assert = 'version-stable-97CA00.svg'; + $badge = Badge::fromURI($assert); + + $this->assertEquals($assert, (string) $badge); + } + + public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnderscores(): void + { + $input = 'I__m__liugg__io-b-97CA00.svg'; + $assertInput = 'I_m_liugg_io-b-97CA00.svg'; + $badge = Badge::fromURI($input); + + $this->assertEquals($assertInput, (string) $badge); + } + + public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithSingleUnderscore(): void + { + $input = 'I_m_liuggio-b-97CA00.svg'; + $assertInput = 'I m liuggio-b-97CA00.svg'; + $badge = Badge::fromURI($input); + + $this->assertEquals($assertInput, (string) $badge); + } + + public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithDashes(): void + { + $input = 'I--m--liuggio-b-97CA00.svg'; + $assertInput = 'I-m-liuggio-b-97CA00.svg'; + $badge = Badge::fromURI($input); + + $this->assertEquals($assertInput, (string) $badge); + } + + /** + * @dataProvider positiveConversionExamples + */ + public function testShouldValidateAvailableColorSchemes(string $colorName): void + { + $badge = new Badge('a', 'b', $colorName, 'flat'); + $this->assertIsString($badge->getHexColor()); + } + + public static function positiveConversionExamples(): array + { + $colorNames = Badge::getColorNamesAvailable(); + + $data = []; + foreach ($colorNames as $colorName) { + $data[$colorName] = [$colorName]; + } + + return $data; + } +} diff --git a/tests/Fixtures/flat-square.svg b/tests/Fixtures/flat-square.svg new file mode 100644 index 00000000..6e7903c5 --- /dev/null +++ b/tests/Fixtures/flat-square.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + license + license + MIT + MIT + + diff --git a/tests/Fixtures/flat.svg b/tests/Fixtures/flat.svg new file mode 100644 index 00000000..a86cc245 --- /dev/null +++ b/tests/Fixtures/flat.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + license + license + MIT + MIT + + diff --git a/tests/Fixtures/invalid_template/plastic.svg b/tests/Fixtures/invalid_template/plastic.svg new file mode 100644 index 00000000..94b2a65f --- /dev/null +++ b/tests/Fixtures/invalid_template/plastic.svg @@ -0,0 +1,13 @@ + + + + + + + + + stable + stable + v2.0 + v2.0 + diff --git a/tests/Fixtures/license.svg b/tests/Fixtures/license.svg new file mode 100644 index 00000000..4bfc0827 --- /dev/null +++ b/tests/Fixtures/license.svg @@ -0,0 +1,14 @@ + + + + + + + + + stable + stable + v2.0 + v2.0 + + diff --git a/tests/Fixtures/xml_template/plastic.svg b/tests/Fixtures/xml_template/plastic.svg new file mode 100644 index 00000000..0ec22255 --- /dev/null +++ b/tests/Fixtures/xml_template/plastic.svg @@ -0,0 +1,26 @@ + + + + PHP: Behind the Parser + + + Ms. Coder + Onlivia Actora + + + Mr. Coder + El ActÓr + + + + So, this language. It's like, a programming language. Or is it a + scripting language? All is revealed in this thrilling horror spoof + of a documentary. + + + PHP solves all my web problems + + 7 + 5 + + diff --git a/tests/PoserTest.php b/tests/PoserTest.php new file mode 100644 index 00000000..a052a2a7 --- /dev/null +++ b/tests/PoserTest.php @@ -0,0 +1,83 @@ +poser = new Poser([ + new SvgFlatRender(), + new SvgFlatSquareRender(), + ]); + } + + public function testIsInitializable(): void + { + $this->assertInstanceOf(Poser::class, $this->poser); + } + + public function testShouldBeAbleToGenerateAnSvgImage(): void + { + $subject = 'stable'; + $status = 'v2.0'; + $color = '97CA00'; + $style = 'flat'; + $format = 'svg'; + + $image = $this->poser->generate($subject, $status, $color, $style, $format); + + $this->assertValidSVGImageContaining((string) $image, $subject, $status); + } + + public function testShouldBeAbleToGenerateAnSvgImageFromURI(): void + { + $subject = 'stable-v2.0-97CA00.svg'; + + $image = $this->poser->generateFromURI($subject); + + $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); + } + + public function testShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension(): void + { + $subject = 'stable-v2.0-97CA00'; + + $image = $this->poser->generateFromURI($subject); + + $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); + } + + public function testShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void + { + $subject = 'stable-v2.0-97CA00.svg?style=flat-square'; + + $image = $this->poser->generateFromURI($subject); + + $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); + } + + public function testShouldThrowExceptionOnGenerateAnSvgImageWithBadURI(): void + { + $subject = 'stable-v2.0-'; + + $this->expectException(\InvalidArgumentException::class); + $this->poser->generateFromURI($subject); + } + + private function assertValidSVGImageContaining(string $svg, string $subject, string $status): void + { + $regex = '/^$/'; + + $this->assertMatchesRegularExpression($regex, $svg); + } +} diff --git a/tests/Render/SvgFlatRenderTest.php b/tests/Render/SvgFlatRenderTest.php new file mode 100644 index 00000000..cd406e78 --- /dev/null +++ b/tests/Render/SvgFlatRenderTest.php @@ -0,0 +1,52 @@ +calculator = $this->createMock(TextSizeCalculatorInterface::class); + $this->calculator->method('calculateWidth')->willReturn(20.0); + $this->render = new SvgFlatRender($this->calculator); + } + + public function testShouldRenderASvg(): void + { + $badge = Badge::fromURI('version-stable-97CA00.svg'); + $image = $this->render->render($badge); + + $this->assertValidSVGImage((string) $image); + } + + public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void + { + $fixture = __DIR__ . '/../Fixtures/flat.svg'; + $template = \file_get_contents($fixture); + $badge = Badge::fromURI('license-MIT-blue.svg'); + $image = $this->render->render($badge); + + $this->assertEquals($template, (string) $image); + } + + public function testGetBadgeStyle(): void + { + $this->assertEquals('flat', $this->render->getBadgeStyle()); + } + + private function assertValidSVGImage(string $svg): void + { + $regex = '/^$/'; + $this->assertMatchesRegularExpression($regex, $svg); + } +} diff --git a/tests/Render/SvgFlatSquareRenderTest.php b/tests/Render/SvgFlatSquareRenderTest.php new file mode 100644 index 00000000..4090c55d --- /dev/null +++ b/tests/Render/SvgFlatSquareRenderTest.php @@ -0,0 +1,52 @@ +calculator = $this->createMock(TextSizeCalculatorInterface::class); + $this->calculator->method('calculateWidth')->willReturn(20.0); + $this->render = new SvgFlatSquareRender($this->calculator); + } + + public function testShouldRenderASvg(): void + { + $badge = Badge::fromURI('version-stable-97CA00.svg?style=flat-square'); + $image = $this->render->render($badge); + + $this->assertValidSVGImage((string) $image); + } + + public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void + { + $fixture = __DIR__ . '/../Fixtures/flat-square.svg'; + $template = \file_get_contents($fixture); + $badge = Badge::fromURI('license-MIT-blue.svg?style=flat-square'); + $image = $this->render->render($badge); + + $this->assertEquals($template, (string) $image); + } + + public function testGetBadgeStyle(): void + { + $this->assertEquals('flat-square', $this->render->getBadgeStyle()); + } + + private function assertValidSVGImage(string $svg): void + { + $regex = '/^$/'; + $this->assertMatchesRegularExpression($regex, $svg); + } +} diff --git a/tests/Render/SvgPlasticRenderTest.php b/tests/Render/SvgPlasticRenderTest.php new file mode 100644 index 00000000..68fda3a1 --- /dev/null +++ b/tests/Render/SvgPlasticRenderTest.php @@ -0,0 +1,66 @@ +calculator = $this->createMock(TextSizeCalculatorInterface::class); + $this->calculator->method('calculateWidth')->willReturn(20.0); + $this->render = new SvgPlasticRender($this->calculator); + } + + public function testShouldRenderASvg(): void + { + $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); + $image = $this->render->render($badge); + + $this->assertValidSVGImage((string) $image); + } + + public function testGetBadgeStyle(): void + { + $this->assertEquals('plastic', $this->render->getBadgeStyle()); + } + + public function testShouldNotRenderAnInvalidSvg(): void + { + $templatesDir = __DIR__ . '/../Fixtures/invalid_template'; + $render = new SvgPlasticRender($this->calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Generated string is not a valid XML'); + + $render->render($badge); + } + + public function testShouldNotRenderNonSvgXml(): void + { + $templatesDir = __DIR__ . '/../Fixtures/xml_template'; + $render = new SvgPlasticRender($this->calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Generated xml is not a SVG'); + + $render->render($badge); + } + + private function assertValidSVGImage(string $svg): void + { + $regex = '/^$/'; + $this->assertMatchesRegularExpression($regex, $svg); + } +} From eb90144eedcbdeee327c0203182b223a729bb8a9 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Sat, 11 Oct 2025 15:08:24 +0200 Subject: [PATCH 02/12] test: Remove PhpSpec --- .github/workflows/php.yml | 7 +- composer.json | 14 --- spec/Fixtures/flat-square.svg | 20 ---- spec/Fixtures/flat.svg | 20 ---- spec/Fixtures/invalid_template/plastic.svg | 13 --- spec/Fixtures/license.svg | 14 --- spec/Fixtures/xml_template/plastic.svg | 26 ----- spec/PUGX/Poser/BadgeSpec.php | 84 ---------------- .../Calculator/GDTextSizeCalculatorSpec.php | 15 --- .../Calculator/SvgTextSizeCalculatorSpec.php | 15 --- spec/PUGX/Poser/PoserSpec.php | 96 ------------------- spec/PUGX/Poser/Render/SvgFlatRenderSpec.php | 44 --------- .../Poser/Render/SvgFlatSquareRenderSpec.php | 44 --------- .../Poser/Render/SvgPlasticRenderSpec.php | 52 ---------- 14 files changed, 2 insertions(+), 462 deletions(-) delete mode 100644 spec/Fixtures/flat-square.svg delete mode 100644 spec/Fixtures/flat.svg delete mode 100644 spec/Fixtures/invalid_template/plastic.svg delete mode 100644 spec/Fixtures/license.svg delete mode 100644 spec/Fixtures/xml_template/plastic.svg delete mode 100644 spec/PUGX/Poser/BadgeSpec.php delete mode 100644 spec/PUGX/Poser/Calculator/GDTextSizeCalculatorSpec.php delete mode 100644 spec/PUGX/Poser/Calculator/SvgTextSizeCalculatorSpec.php delete mode 100644 spec/PUGX/Poser/PoserSpec.php delete mode 100644 spec/PUGX/Poser/Render/SvgFlatRenderSpec.php delete mode 100644 spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php delete mode 100644 spec/PUGX/Poser/Render/SvgPlasticRenderSpec.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 08f75a1d..fd5e2781 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -58,11 +58,8 @@ jobs: - name: Coding Standard Checks run: docker compose run --rm ${{ matrix.container }} bin/php-cs-fixer fix --verbose --diff --dry-run - - name: Run tests (phpspec) - run: docker compose run --rm ${{ matrix.container }} ./bin/phpspec run --format=pretty - - - name: Run coverage tests (phpspec) - run: docker compose run --rm ${{ matrix.container }} bash -c "XDEBUG_MODE=coverage bin/phpspec run -f progress -c phpspec-coverage.yml" + - name: Unit tests + run: ./bin/phpunit - name: Run behat tests run: docker compose run --rm ${{ matrix.container }} ./bin/behat --snippets-for diff --git a/composer.json b/composer.json index 80e0da8c..afc04770 100644 --- a/composer.json +++ b/composer.json @@ -22,15 +22,6 @@ "autoload": { "psr-4": { "PUGX\\Poser\\": "src/" } }, - "autoload-dev": { - "psr-4": { "spec\\PUGX\\": "spec/PUGX/" } - }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/madisoft/phpspec-data-provider-extension" - } - ], "require": { "php": "^8.1", "ext-gd": "*", @@ -41,10 +32,7 @@ }, "require-dev": { "behat/behat": "^3.13", - "friends-of-phpspec/phpspec-code-coverage": "^6.3", "friendsofphp/php-cs-fixer": "^3.41", - "moave/phpspec-data-provider-extension": "dev-master", - "phpspec/phpspec": "^7.4 || ^8.0", "phpunit/phpunit": "@stable", "vimeo/psalm": "^4.30" }, @@ -59,8 +47,6 @@ "scripts": { "php-cs-fixer-dry-run": "bin/php-cs-fixer fix --verbose --diff --dry-run --ansi", "php-cs-fixer": "bin/php-cs-fixer fix -v --ansi", - "phpspec": "bin/phpspec run --format=pretty --ansi", - "phpspec-coverage": "bin/phpspec run -f progress -c phpspec-coverage.yml --ansi", "behat": "bin/behat --snippets-for", "docker:build:php81": "docker build -t pugx/poser:php81 -f .docker/base/php81/Dockerfile .", "docker:push:php81": "docker push pugx/poser:php81", diff --git a/spec/Fixtures/flat-square.svg b/spec/Fixtures/flat-square.svg deleted file mode 100644 index 6e7903c5..00000000 --- a/spec/Fixtures/flat-square.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - license - license - MIT - MIT - - diff --git a/spec/Fixtures/flat.svg b/spec/Fixtures/flat.svg deleted file mode 100644 index a86cc245..00000000 --- a/spec/Fixtures/flat.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - license - license - MIT - MIT - - diff --git a/spec/Fixtures/invalid_template/plastic.svg b/spec/Fixtures/invalid_template/plastic.svg deleted file mode 100644 index 94b2a65f..00000000 --- a/spec/Fixtures/invalid_template/plastic.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - stable - stable - v2.0 - v2.0 - diff --git a/spec/Fixtures/license.svg b/spec/Fixtures/license.svg deleted file mode 100644 index 4bfc0827..00000000 --- a/spec/Fixtures/license.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - stable - stable - v2.0 - v2.0 - - diff --git a/spec/Fixtures/xml_template/plastic.svg b/spec/Fixtures/xml_template/plastic.svg deleted file mode 100644 index 0ec22255..00000000 --- a/spec/Fixtures/xml_template/plastic.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - PHP: Behind the Parser - - - Ms. Coder - Onlivia Actora - - - Mr. Coder - El ActÓr - - - - So, this language. It's like, a programming language. Or is it a - scripting language? All is revealed in this thrilling horror spoof - of a documentary. - - - PHP solves all my web problems - - 7 - 5 - - diff --git a/spec/PUGX/Poser/BadgeSpec.php b/spec/PUGX/Poser/BadgeSpec.php deleted file mode 100644 index b0c4d281..00000000 --- a/spec/PUGX/Poser/BadgeSpec.php +++ /dev/null @@ -1,84 +0,0 @@ -beConstructedWith('a', 'b', '97CA00', 'flat'); - $this->shouldHaveType(Badge::class); - } - - public function it_should_be_constructed_by_fromURI_factory_method(): void - { - $this->beConstructedWith('a', 'b', '97CA00', 'flat'); - $assert = 'version-stable-97CA00.svg'; - $it = Badge::fromURI($assert); - - if ((string) $it !== $assert) { - throw new Exception(\sprintf("from[%s] having[%s]\n", $assert, (string) $it)); - } - } - - public function it_should_be_constructed_by_fromURI_factory_method_escaping_correctly_underscores(): void - { - $this->beConstructedWith('a', 'b', '97CA00', 'flat'); - $input = 'I__m__liugg__io-b-97CA00.svg'; - $assertInput = 'I_m_liugg_io-b-97CA00.svg'; - $it = Badge::fromURI($input); - - if ((string) $it !== $assertInput) { - throw new Exception(\sprintf("from[%s] wants[%s] having[%s]\n", $input, $assertInput, (string) $it)); - } - } - - public function it_should_be_constructed_by_fromURI_factory_method_escaping_correctly_with_single_underscore(): void - { - $this->beConstructedWith('a', 'b', '97CA00', 'flat'); - $input = 'I_m_liuggio-b-97CA00.svg'; - $assertInput = 'I m liuggio-b-97CA00.svg'; - $it = Badge::fromURI($input); - - if ((string) $it !== $assertInput) { - throw new Exception(\sprintf("from[%s] wants[%s] having[%s]\n", $input, $assertInput, (string) $it)); - } - } - - public function it_should_be_constructed_by_fromURI_factory_method_escaping_correctly_with_dashes(): void - { - $this->beConstructedWith('a', 'b', '97CA00', 'flat'); - $input = 'I--m--liuggio-b-97CA00.svg'; - $assertInput = 'I-m-liuggio-b-97CA00.svg'; - $it = Badge::fromURI($input); - - if ((string) $it !== $assertInput) { - throw new Exception(\sprintf("from[%s] wants[%s] having[%s]\n", $input, $assertInput, (string) $it)); - } - } - - /** - * @dataProvider positiveConversionExamples - */ - public function it_should_validate_available_color_schemes($colorName, $expectedValue): void - { - $this->beConstructedWith('a', 'b', $colorName, 'flat'); - $this->getHexColor()->shouldBeString(); - } - - public function positiveConversionExamples() - { - $colorNames = Badge::getColorNamesAvailable(); - - $data = []; - foreach ($colorNames as $colorName) { - $data[] = [$colorName, null]; - } - - return $data; - } -} diff --git a/spec/PUGX/Poser/Calculator/GDTextSizeCalculatorSpec.php b/spec/PUGX/Poser/Calculator/GDTextSizeCalculatorSpec.php deleted file mode 100644 index 64e1127b..00000000 --- a/spec/PUGX/Poser/Calculator/GDTextSizeCalculatorSpec.php +++ /dev/null @@ -1,15 +0,0 @@ -calculateWidth('MIT', 8)->shouldBeLike(24.0); - $this->calculateWidth('MIT', 10)->shouldBeLike(29.0); - $this->calculateWidth('MIT', 14)->shouldBeLike(34.0); - } -} diff --git a/spec/PUGX/Poser/Calculator/SvgTextSizeCalculatorSpec.php b/spec/PUGX/Poser/Calculator/SvgTextSizeCalculatorSpec.php deleted file mode 100644 index 7930d3bf..00000000 --- a/spec/PUGX/Poser/Calculator/SvgTextSizeCalculatorSpec.php +++ /dev/null @@ -1,15 +0,0 @@ -calculateWidth('MIT', 8)->shouldBeLike(24.1); - $this->calculateWidth('MIT', 10)->shouldBeLike(27.7); - $this->calculateWidth('MIT', 14)->shouldBeLike(34.8); - } -} diff --git a/spec/PUGX/Poser/PoserSpec.php b/spec/PUGX/Poser/PoserSpec.php deleted file mode 100644 index 85665ceb..00000000 --- a/spec/PUGX/Poser/PoserSpec.php +++ /dev/null @@ -1,96 +0,0 @@ -beConstructedWith([ - new SvgFlatRender(), - new SvgFlatSquareRender(), - ]); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(Poser::class); - } - - public function it_should_be_able_to_generate_an_svg_image(): void - { - $subject = 'stable'; - $status = 'v2.0'; - $color = '97CA00'; - $style = 'flat'; - $format = 'svg'; - - $this->generate($subject, $status, $color, $style, $format)->shouldBeAValidSVGImageContaining($subject, $status); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI(): void - { - $subject = 'stable-v2.0-97CA00.svg'; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI_without_file_extension(): void - { - $subject = 'stable-v2.0-97CA00'; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI_with_style(): void - { - $subject = 'stable-v2.0-97CA00.svg?style=flat-square'; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI_with_empty_style(): void - { - $subject = 'stable-v2.0-97CA00.svg?style='; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI_with_empty_query(): void - { - $subject = 'stable-v2.0-97CA00.svg?'; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_be_able_to_generate_an_svg_image_from_URI_without_file_extension_with_style(): void - { - $subject = 'stable-v2.0-97CA00?style=flat-square'; - - $this->generateFromURI($subject)->shouldBeAValidSVGImageContaining('stable', 'v2.0'); - } - - public function it_should_throw_exception_on_generate_an_svg_image_with_bad_uri(): void - { - $subject = 'stable-v2.0-'; - - $this->shouldThrow(\InvalidArgumentException::class)->during('generateFromURI', [$subject]); - } - - public function getMatchers(): array - { - return [ - 'beAValidSVGImageContaining' => function ($object, $subject, $status) { - $regex = '/^$/'; - $matches = []; - - return \preg_match($regex, $object, $matches, \PREG_OFFSET_CAPTURE, 0); - }, - ]; - } -} diff --git a/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php b/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php deleted file mode 100644 index 195f17c1..00000000 --- a/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php +++ /dev/null @@ -1,44 +0,0 @@ -beADoubleOf(TextSizeCalculatorInterface::class); - $calculator->calculateWidth(Argument::any())->willReturn(20); - $this->beConstructedWith($calculator); - } - - public function it_should_render_a_svg(): void - { - $badge = Badge::fromURI('version-stable-97CA00.svg'); - $this->render($badge)->shouldBeAValidSVGImage(); - } - - public function getMatchers(): array - { - return [ - 'beAValidSVGImage' => function ($subject) { - $regex = '/^$/'; - $matches = []; - - return \preg_match($regex, (string) $subject, $matches, \PREG_OFFSET_CAPTURE, 0); - }, - ]; - } - - public function it_should_render_a_license_mit_exactly_like_this_svg(): void - { - $fixture = __DIR__ . '/../../../Fixtures/flat.svg'; - $template = \file_get_contents($fixture); - $badge = Badge::fromURI('license-MIT-blue.svg'); - $this->render($badge)->__toString()->shouldBeLike($template); - } -} diff --git a/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php b/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php deleted file mode 100644 index 20108c44..00000000 --- a/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php +++ /dev/null @@ -1,44 +0,0 @@ -beADoubleOf(TextSizeCalculatorInterface::class); - $calculator->calculateWidth(Argument::any())->willReturn(20); - $this->beConstructedWith($calculator); - } - - public function it_should_render_a_svg(): void - { - $badge = Badge::fromURI('version-stable-97CA00.svg'); - $this->render($badge)->shouldBeAValidSVGImage(); - } - - public function getMatchers(): array - { - return [ - 'beAValidSVGImage' => function ($subject) { - $regex = '/^$/'; - $matches = []; - - return \preg_match($regex, (string) $subject, $matches, \PREG_OFFSET_CAPTURE, 0); - }, - ]; - } - - public function it_should_render_a_license_mit_exactly_like_this_svg(): void - { - $fixture = __DIR__ . '/../../../Fixtures/flat-square.svg'; - $template = \file_get_contents($fixture); - $badge = Badge::fromURI('license-MIT-blue.svg'); - $this->render($badge)->__toString()->shouldBeLike($template); - } -} diff --git a/spec/PUGX/Poser/Render/SvgPlasticRenderSpec.php b/spec/PUGX/Poser/Render/SvgPlasticRenderSpec.php deleted file mode 100644 index 061f98e8..00000000 --- a/spec/PUGX/Poser/Render/SvgPlasticRenderSpec.php +++ /dev/null @@ -1,52 +0,0 @@ -beADoubleOf(TextSizeCalculatorInterface::class); - $calculator->calculateWidth(Argument::any())->willReturn(20); - $this->beConstructedWith($calculator); - } - - public function it_should_render_a_svg(): void - { - $badge = Badge::fromURI('version-stable-97CA00.svg'); - $this->render($badge)->shouldBeAValidSVGImage(); - } - - public function it_should_not_render_an_invalid_svg($calculator): void - { - $templatesDir = __DIR__ . '/../../../Fixtures/invalid_template'; - $this->beConstructedWith($calculator, $templatesDir); - $badge = Badge::fromURI('version-stable-97CA00.svg'); - $this->shouldThrow(new \RuntimeException('Generated string is not a valid XML'))->duringRender($badge); - } - - public function it_should_not_render_non_svg_xml($calculator): void - { - $templatesDir = __DIR__ . '/../../../Fixtures/xml_template'; - $this->beConstructedWith($calculator, $templatesDir); - $badge = Badge::fromURI('version-stable-97CA00.svg'); - $this->shouldThrow(new \RuntimeException('Generated xml is not a SVG'))->duringRender($badge); - } - - public function getMatchers(): array - { - return [ - 'beAValidSVGImage' => function ($subject) { - $regex = '/^$/'; - $matches = []; - - return \preg_match($regex, (string) $subject, $matches, \PREG_OFFSET_CAPTURE, 0); - }, - ]; - } -} From 98d9211edf289796339516f9c3ee24097fb5fca2 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Sat, 11 Oct 2025 15:30:23 +0200 Subject: [PATCH 03/12] test: Add Calculator unit tests --- tests/Calculator/GDTextSizeCalculatorTest.php | 43 +++++++++++++++++++ .../Calculator/SvgTextSizeCalculatorTest.php | 43 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tests/Calculator/GDTextSizeCalculatorTest.php create mode 100644 tests/Calculator/SvgTextSizeCalculatorTest.php diff --git a/tests/Calculator/GDTextSizeCalculatorTest.php b/tests/Calculator/GDTextSizeCalculatorTest.php new file mode 100644 index 00000000..fb57de6e --- /dev/null +++ b/tests/Calculator/GDTextSizeCalculatorTest.php @@ -0,0 +1,43 @@ +calculator = new GDTextSizeCalculator(); + } + + public function testShouldComputeTextWidthWithSize8(): void + { + $width = $this->calculator->calculateWidth('MIT', 8); + $this->assertEquals(24.0, $width); + } + + public function testShouldComputeTextWidthWithSize10(): void + { + $width = $this->calculator->calculateWidth('MIT', 10); + $this->assertEquals(29.0, $width); + } + + public function testShouldComputeTextWidthWithSize14(): void + { + $width = $this->calculator->calculateWidth('MIT', 14); + $this->assertEquals(34.0, $width); + } + + public function testShouldComputeTextWidthWithDefaultSize(): void + { + $width = $this->calculator->calculateWidth('MIT'); + $this->assertIsFloat($width); + $this->assertGreaterThan(0, $width); + } +} diff --git a/tests/Calculator/SvgTextSizeCalculatorTest.php b/tests/Calculator/SvgTextSizeCalculatorTest.php new file mode 100644 index 00000000..ab152547 --- /dev/null +++ b/tests/Calculator/SvgTextSizeCalculatorTest.php @@ -0,0 +1,43 @@ +calculator = new SvgTextSizeCalculator(); + } + + public function testShouldComputeTextWidthWithSize8(): void + { + $width = $this->calculator->calculateWidth('MIT', 8); + $this->assertEquals(24.1, $width); + } + + public function testShouldComputeTextWidthWithSize10(): void + { + $width = $this->calculator->calculateWidth('MIT', 10); + $this->assertEquals(27.7, $width); + } + + public function testShouldComputeTextWidthWithSize14(): void + { + $width = $this->calculator->calculateWidth('MIT', 14); + $this->assertEquals(34.8, $width); + } + + public function testShouldComputeTextWidthWithDefaultSize(): void + { + $width = $this->calculator->calculateWidth('MIT'); + $this->assertIsFloat($width); + $this->assertGreaterThan(0, $width); + } +} From c0359ec259975b088c6158747ef04250f8a6c0dc Mon Sep 17 00:00:00 2001 From: jmleroux Date: Mon, 13 Oct 2025 18:39:31 +0200 Subject: [PATCH 04/12] fix: Lint fix --- tests/BadgeTest.php | 14 +++++++------- tests/PoserTest.php | 8 ++++---- tests/Render/SvgFlatRenderTest.php | 6 +++--- tests/Render/SvgFlatSquareRenderTest.php | 6 +++--- tests/Render/SvgPlasticRenderTest.php | 8 ++++---- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/BadgeTest.php b/tests/BadgeTest.php index 7f022fbd..8c780c84 100644 --- a/tests/BadgeTest.php +++ b/tests/BadgeTest.php @@ -18,34 +18,34 @@ public function testIsInitializable(): void public function testShouldBeConstructedByFromURIFactoryMethod(): void { $assert = 'version-stable-97CA00.svg'; - $badge = Badge::fromURI($assert); + $badge = Badge::fromURI($assert); $this->assertEquals($assert, (string) $badge); } public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnderscores(): void { - $input = 'I__m__liugg__io-b-97CA00.svg'; + $input = 'I__m__liugg__io-b-97CA00.svg'; $assertInput = 'I_m_liugg_io-b-97CA00.svg'; - $badge = Badge::fromURI($input); + $badge = Badge::fromURI($input); $this->assertEquals($assertInput, (string) $badge); } public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithSingleUnderscore(): void { - $input = 'I_m_liuggio-b-97CA00.svg'; + $input = 'I_m_liuggio-b-97CA00.svg'; $assertInput = 'I m liuggio-b-97CA00.svg'; - $badge = Badge::fromURI($input); + $badge = Badge::fromURI($input); $this->assertEquals($assertInput, (string) $badge); } public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithDashes(): void { - $input = 'I--m--liuggio-b-97CA00.svg'; + $input = 'I--m--liuggio-b-97CA00.svg'; $assertInput = 'I-m-liuggio-b-97CA00.svg'; - $badge = Badge::fromURI($input); + $badge = Badge::fromURI($input); $this->assertEquals($assertInput, (string) $badge); } diff --git a/tests/PoserTest.php b/tests/PoserTest.php index a052a2a7..9ef13470 100644 --- a/tests/PoserTest.php +++ b/tests/PoserTest.php @@ -29,10 +29,10 @@ public function testIsInitializable(): void public function testShouldBeAbleToGenerateAnSvgImage(): void { $subject = 'stable'; - $status = 'v2.0'; - $color = '97CA00'; - $style = 'flat'; - $format = 'svg'; + $status = 'v2.0'; + $color = '97CA00'; + $style = 'flat'; + $format = 'svg'; $image = $this->poser->generate($subject, $status, $color, $style, $format); diff --git a/tests/Render/SvgFlatRenderTest.php b/tests/Render/SvgFlatRenderTest.php index cd406e78..7e3e078d 100644 --- a/tests/Render/SvgFlatRenderTest.php +++ b/tests/Render/SvgFlatRenderTest.php @@ -31,10 +31,10 @@ public function testShouldRenderASvg(): void public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void { - $fixture = __DIR__ . '/../Fixtures/flat.svg'; + $fixture = __DIR__ . '/../Fixtures/flat.svg'; $template = \file_get_contents($fixture); - $badge = Badge::fromURI('license-MIT-blue.svg'); - $image = $this->render->render($badge); + $badge = Badge::fromURI('license-MIT-blue.svg'); + $image = $this->render->render($badge); $this->assertEquals($template, (string) $image); } diff --git a/tests/Render/SvgFlatSquareRenderTest.php b/tests/Render/SvgFlatSquareRenderTest.php index 4090c55d..3508331d 100644 --- a/tests/Render/SvgFlatSquareRenderTest.php +++ b/tests/Render/SvgFlatSquareRenderTest.php @@ -31,10 +31,10 @@ public function testShouldRenderASvg(): void public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void { - $fixture = __DIR__ . '/../Fixtures/flat-square.svg'; + $fixture = __DIR__ . '/../Fixtures/flat-square.svg'; $template = \file_get_contents($fixture); - $badge = Badge::fromURI('license-MIT-blue.svg?style=flat-square'); - $image = $this->render->render($badge); + $badge = Badge::fromURI('license-MIT-blue.svg?style=flat-square'); + $image = $this->render->render($badge); $this->assertEquals($template, (string) $image); } diff --git a/tests/Render/SvgPlasticRenderTest.php b/tests/Render/SvgPlasticRenderTest.php index 68fda3a1..f47ee110 100644 --- a/tests/Render/SvgPlasticRenderTest.php +++ b/tests/Render/SvgPlasticRenderTest.php @@ -37,8 +37,8 @@ public function testGetBadgeStyle(): void public function testShouldNotRenderAnInvalidSvg(): void { $templatesDir = __DIR__ . '/../Fixtures/invalid_template'; - $render = new SvgPlasticRender($this->calculator, $templatesDir); - $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); + $render = new SvgPlasticRender($this->calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Generated string is not a valid XML'); @@ -49,8 +49,8 @@ public function testShouldNotRenderAnInvalidSvg(): void public function testShouldNotRenderNonSvgXml(): void { $templatesDir = __DIR__ . '/../Fixtures/xml_template'; - $render = new SvgPlasticRender($this->calculator, $templatesDir); - $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); + $render = new SvgPlasticRender($this->calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Generated xml is not a SVG'); From 94638ed44e34558f7a5acdfe8a74da9770fb82fd Mon Sep 17 00:00:00 2001 From: jmleroux Date: Mon, 13 Oct 2025 18:54:46 +0200 Subject: [PATCH 05/12] test: Use test annotation and "it" prefix. --- .php-cs-fixer.php | 1 + composer.json | 5 +++- phpunit.xml | 10 +++---- tests/BadgeTest.php | 29 ++++++++++++++---- tests/Calculator/GDTextSizeCalculatorTest.php | 20 ++++++++++--- .../Calculator/SvgTextSizeCalculatorTest.php | 20 ++++++++++--- tests/PoserTest.php | 30 +++++++++++++++---- tests/Render/SvgFlatRenderTest.php | 15 ++++++++-- tests/Render/SvgFlatSquareRenderTest.php | 15 ++++++++-- tests/Render/SvgPlasticRenderTest.php | 20 ++++++++++--- 10 files changed, 128 insertions(+), 37 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 98e099bd..8da699fe 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -18,6 +18,7 @@ 'binary_operator_spaces' => ['operators' => ['=>' => 'align', '=' => 'align']], 'phpdoc_align' => ['align' => 'vertical'], 'phpdoc_summary' => false, + 'php_unit_test_annotation' => ['style' => 'annotation'], ]) ->setFinder($finder) ; diff --git a/composer.json b/composer.json index afc04770..1c539ecc 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,9 @@ "autoload": { "psr-4": { "PUGX\\Poser\\": "src/" } }, + "autoload-dev": { + "psr-4": { "PUGX\\Poser\\Tests\\": "tests/" } + }, "require": { "php": "^8.1", "ext-gd": "*", @@ -33,7 +36,7 @@ "require-dev": { "behat/behat": "^3.13", "friendsofphp/php-cs-fixer": "^3.41", - "phpunit/phpunit": "@stable", + "phpunit/phpunit": "^9.6", "vimeo/psalm": "^4.30" }, "config": { diff --git a/phpunit.xml b/phpunit.xml index a1992819..2ae4a9aa 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,20 +1,18 @@ + beStrictAboutOutputDuringTests="true"> tests - + src - + diff --git a/tests/BadgeTest.php b/tests/BadgeTest.php index 8c780c84..1532dd02 100644 --- a/tests/BadgeTest.php +++ b/tests/BadgeTest.php @@ -9,13 +9,19 @@ class BadgeTest extends TestCase { - public function testIsInitializable(): void + /** + * @test + */ + public function itIsInitializable(): void { $badge = new Badge('a', 'b', '97CA00', 'flat'); $this->assertInstanceOf(Badge::class, $badge); } - public function testShouldBeConstructedByFromURIFactoryMethod(): void + /** + * @test + */ + public function itShouldBeConstructedByFromURIFactoryMethod(): void { $assert = 'version-stable-97CA00.svg'; $badge = Badge::fromURI($assert); @@ -23,7 +29,10 @@ public function testShouldBeConstructedByFromURIFactoryMethod(): void $this->assertEquals($assert, (string) $badge); } - public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnderscores(): void + /** + * @test + */ + public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnderscores(): void { $input = 'I__m__liugg__io-b-97CA00.svg'; $assertInput = 'I_m_liugg_io-b-97CA00.svg'; @@ -32,7 +41,10 @@ public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUn $this->assertEquals($assertInput, (string) $badge); } - public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithSingleUnderscore(): void + /** + * @test + */ + public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithSingleUnderscore(): void { $input = 'I_m_liuggio-b-97CA00.svg'; $assertInput = 'I m liuggio-b-97CA00.svg'; @@ -41,7 +53,10 @@ public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWi $this->assertEquals($assertInput, (string) $badge); } - public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithDashes(): void + /** + * @test + */ + public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithDashes(): void { $input = 'I--m--liuggio-b-97CA00.svg'; $assertInput = 'I-m-liuggio-b-97CA00.svg'; @@ -51,9 +66,11 @@ public function testShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWi } /** + * @test + * * @dataProvider positiveConversionExamples */ - public function testShouldValidateAvailableColorSchemes(string $colorName): void + public function itShouldValidateAvailableColorSchemes(string $colorName): void { $badge = new Badge('a', 'b', $colorName, 'flat'); $this->assertIsString($badge->getHexColor()); diff --git a/tests/Calculator/GDTextSizeCalculatorTest.php b/tests/Calculator/GDTextSizeCalculatorTest.php index fb57de6e..de153992 100644 --- a/tests/Calculator/GDTextSizeCalculatorTest.php +++ b/tests/Calculator/GDTextSizeCalculatorTest.php @@ -16,25 +16,37 @@ protected function setUp(): void $this->calculator = new GDTextSizeCalculator(); } - public function testShouldComputeTextWidthWithSize8(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize8(): void { $width = $this->calculator->calculateWidth('MIT', 8); $this->assertEquals(24.0, $width); } - public function testShouldComputeTextWidthWithSize10(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize10(): void { $width = $this->calculator->calculateWidth('MIT', 10); $this->assertEquals(29.0, $width); } - public function testShouldComputeTextWidthWithSize14(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize14(): void { $width = $this->calculator->calculateWidth('MIT', 14); $this->assertEquals(34.0, $width); } - public function testShouldComputeTextWidthWithDefaultSize(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithDefaultSize(): void { $width = $this->calculator->calculateWidth('MIT'); $this->assertIsFloat($width); diff --git a/tests/Calculator/SvgTextSizeCalculatorTest.php b/tests/Calculator/SvgTextSizeCalculatorTest.php index ab152547..77071474 100644 --- a/tests/Calculator/SvgTextSizeCalculatorTest.php +++ b/tests/Calculator/SvgTextSizeCalculatorTest.php @@ -16,25 +16,37 @@ protected function setUp(): void $this->calculator = new SvgTextSizeCalculator(); } - public function testShouldComputeTextWidthWithSize8(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize8(): void { $width = $this->calculator->calculateWidth('MIT', 8); $this->assertEquals(24.1, $width); } - public function testShouldComputeTextWidthWithSize10(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize10(): void { $width = $this->calculator->calculateWidth('MIT', 10); $this->assertEquals(27.7, $width); } - public function testShouldComputeTextWidthWithSize14(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithSize14(): void { $width = $this->calculator->calculateWidth('MIT', 14); $this->assertEquals(34.8, $width); } - public function testShouldComputeTextWidthWithDefaultSize(): void + /** + * @test + */ + public function itShouldComputeTextWidthWithDefaultSize(): void { $width = $this->calculator->calculateWidth('MIT'); $this->assertIsFloat($width); diff --git a/tests/PoserTest.php b/tests/PoserTest.php index 9ef13470..884700a3 100644 --- a/tests/PoserTest.php +++ b/tests/PoserTest.php @@ -21,12 +21,18 @@ protected function setUp(): void ]); } - public function testIsInitializable(): void + /** + * @test + */ + public function itIsInitializable(): void { $this->assertInstanceOf(Poser::class, $this->poser); } - public function testShouldBeAbleToGenerateAnSvgImage(): void + /** + * @test + */ + public function itShouldBeAbleToGenerateAnSvgImage(): void { $subject = 'stable'; $status = 'v2.0'; @@ -39,7 +45,10 @@ public function testShouldBeAbleToGenerateAnSvgImage(): void $this->assertValidSVGImageContaining((string) $image, $subject, $status); } - public function testShouldBeAbleToGenerateAnSvgImageFromURI(): void + /** + * @test + */ + public function itShouldBeAbleToGenerateAnSvgImageFromURI(): void { $subject = 'stable-v2.0-97CA00.svg'; @@ -48,7 +57,10 @@ public function testShouldBeAbleToGenerateAnSvgImageFromURI(): void $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - public function testShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension(): void + /** + * @test + */ + public function itShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension(): void { $subject = 'stable-v2.0-97CA00'; @@ -57,7 +69,10 @@ public function testShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension( $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - public function testShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void + /** + * @test + */ + public function itShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void { $subject = 'stable-v2.0-97CA00.svg?style=flat-square'; @@ -66,7 +81,10 @@ public function testShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - public function testShouldThrowExceptionOnGenerateAnSvgImageWithBadURI(): void + /** + * @test + */ + public function itThrowsExceptionWhenGeneratingAnSvgImageWithBadURI(): void { $subject = 'stable-v2.0-'; diff --git a/tests/Render/SvgFlatRenderTest.php b/tests/Render/SvgFlatRenderTest.php index 7e3e078d..67729c83 100644 --- a/tests/Render/SvgFlatRenderTest.php +++ b/tests/Render/SvgFlatRenderTest.php @@ -21,7 +21,10 @@ protected function setUp(): void $this->render = new SvgFlatRender($this->calculator); } - public function testShouldRenderASvg(): void + /** + * @test + */ + public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg'); $image = $this->render->render($badge); @@ -29,7 +32,10 @@ public function testShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void + /** + * @test + */ + public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void { $fixture = __DIR__ . '/../Fixtures/flat.svg'; $template = \file_get_contents($fixture); @@ -39,7 +45,10 @@ public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void $this->assertEquals($template, (string) $image); } - public function testGetBadgeStyle(): void + /** + * @test + */ + public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('flat', $this->render->getBadgeStyle()); } diff --git a/tests/Render/SvgFlatSquareRenderTest.php b/tests/Render/SvgFlatSquareRenderTest.php index 3508331d..0c53f90c 100644 --- a/tests/Render/SvgFlatSquareRenderTest.php +++ b/tests/Render/SvgFlatSquareRenderTest.php @@ -21,7 +21,10 @@ protected function setUp(): void $this->render = new SvgFlatSquareRender($this->calculator); } - public function testShouldRenderASvg(): void + /** + * @test + */ + public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg?style=flat-square'); $image = $this->render->render($badge); @@ -29,7 +32,10 @@ public function testShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void + /** + * @test + */ + public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void { $fixture = __DIR__ . '/../Fixtures/flat-square.svg'; $template = \file_get_contents($fixture); @@ -39,7 +45,10 @@ public function testShouldRenderALicenseMitExactlyLikeThisSvg(): void $this->assertEquals($template, (string) $image); } - public function testGetBadgeStyle(): void + /** + * @test + */ + public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('flat-square', $this->render->getBadgeStyle()); } diff --git a/tests/Render/SvgPlasticRenderTest.php b/tests/Render/SvgPlasticRenderTest.php index f47ee110..e7c5827b 100644 --- a/tests/Render/SvgPlasticRenderTest.php +++ b/tests/Render/SvgPlasticRenderTest.php @@ -21,7 +21,10 @@ protected function setUp(): void $this->render = new SvgPlasticRender($this->calculator); } - public function testShouldRenderASvg(): void + /** + * @test + */ + public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); $image = $this->render->render($badge); @@ -29,12 +32,18 @@ public function testShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - public function testGetBadgeStyle(): void + /** + * @test + */ + public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('plastic', $this->render->getBadgeStyle()); } - public function testShouldNotRenderAnInvalidSvg(): void + /** + * @test + */ + public function itThrowsExceptionWhenRenderingInvalidSvg(): void { $templatesDir = __DIR__ . '/../Fixtures/invalid_template'; $render = new SvgPlasticRender($this->calculator, $templatesDir); @@ -46,7 +55,10 @@ public function testShouldNotRenderAnInvalidSvg(): void $render->render($badge); } - public function testShouldNotRenderNonSvgXml(): void + /** + * @test + */ + public function itThrowsExceptionWhenRenderingNonSvgXml(): void { $templatesDir = __DIR__ . '/../Fixtures/xml_template'; $render = new SvgPlasticRender($this->calculator, $templatesDir); From 12b67ac292a97e72c2624ca4df13e2a3df8d5582 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Mon, 13 Oct 2025 19:02:18 +0200 Subject: [PATCH 06/12] test: Remove phpspec config files --- CHANGELOG.md | 12 ++++++++++++ phpspec-coverage.yml | 9 --------- phpspec.yml | 3 --- 3 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 phpspec-coverage.yml delete mode 100644 phpspec.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a8fff35..7f22c4b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [v3.2.0] - 2025-10-13 + +### Added +* add phpunit/phpunit composer dependency + +### Removed +* remove PhpSpec + +### Changed +* convert specs to PhpUnit tests + + ## [v3.1.0] - 2024-01-07 ### Added diff --git a/phpspec-coverage.yml b/phpspec-coverage.yml deleted file mode 100644 index fcc7bf13..00000000 --- a/phpspec-coverage.yml +++ /dev/null @@ -1,9 +0,0 @@ -extensions: - Coduo\PhpSpec\DataProvider\DataProviderExtension: ~ - FriendsOfPhpSpec\PhpSpec\CodeCoverage\CodeCoverageExtension: - format: - - html - - php - output: - html: coverage/phpspec-html - php: coverage/phpspec-php/phpspec.cov diff --git a/phpspec.yml b/phpspec.yml deleted file mode 100644 index 7b688c46..00000000 --- a/phpspec.yml +++ /dev/null @@ -1,3 +0,0 @@ -extensions: - Coduo\PhpSpec\DataProvider\DataProviderExtension: ~ - From d3eaf3d288c679ee0cb3bf050ca9a528da2ade83 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Mon, 13 Oct 2025 19:10:18 +0200 Subject: [PATCH 07/12] ci: Code coverage --- .github/workflows/php.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index fd5e2781..a5f27711 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -61,5 +61,8 @@ jobs: - name: Unit tests run: ./bin/phpunit + - name: Unit tests with coverage + run: XDEBUG_MODE=coverage ./bin/phpunit --coverage-clover coverage.xml + - name: Run behat tests run: docker compose run --rm ${{ matrix.container }} ./bin/behat --snippets-for From 8efbd3d3e40bd5895f26f9ccebdfff2ba4886880 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Tue, 14 Oct 2025 18:33:58 +0200 Subject: [PATCH 08/12] chore: change php unit dependency. update psalm to be compatible. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1c539ecc..93ffbcd8 100644 --- a/composer.json +++ b/composer.json @@ -36,8 +36,8 @@ "require-dev": { "behat/behat": "^3.13", "friendsofphp/php-cs-fixer": "^3.41", - "phpunit/phpunit": "^9.6", - "vimeo/psalm": "^4.30" + "phpunit/phpunit": "^10.5 | ^11.5 | ^12.0", + "vimeo/psalm": "^6.13" }, "config": { "bin-dir": "bin", From ea3722b74cd3b4cc2693e9e834ec851e1ef99430 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Tue, 14 Oct 2025 19:49:06 +0200 Subject: [PATCH 09/12] chore: PHP attributes for tests --- tests/BadgeTest.php | 29 ++++++------------- tests/Calculator/GDTextSizeCalculatorTest.php | 17 ++++------- .../Calculator/SvgTextSizeCalculatorTest.php | 17 ++++------- tests/PoserTest.php | 25 +++++----------- tests/Render/SvgFlatRenderTest.php | 13 +++------ tests/Render/SvgFlatSquareRenderTest.php | 13 +++------ tests/Render/SvgPlasticRenderTest.php | 17 ++++------- 7 files changed, 39 insertions(+), 92 deletions(-) diff --git a/tests/BadgeTest.php b/tests/BadgeTest.php index 1532dd02..04a7e55a 100644 --- a/tests/BadgeTest.php +++ b/tests/BadgeTest.php @@ -4,23 +4,21 @@ namespace PUGX\Poser\Tests; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Badge; class BadgeTest extends TestCase { - /** - * @test - */ + #[Test] public function itIsInitializable(): void { $badge = new Badge('a', 'b', '97CA00', 'flat'); $this->assertInstanceOf(Badge::class, $badge); } - /** - * @test - */ + #[Test] public function itShouldBeConstructedByFromURIFactoryMethod(): void { $assert = 'version-stable-97CA00.svg'; @@ -29,9 +27,7 @@ public function itShouldBeConstructedByFromURIFactoryMethod(): void $this->assertEquals($assert, (string) $badge); } - /** - * @test - */ + #[Test] public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnderscores(): void { $input = 'I__m__liugg__io-b-97CA00.svg'; @@ -41,9 +37,7 @@ public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyUnde $this->assertEquals($assertInput, (string) $badge); } - /** - * @test - */ + #[Test] public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithSingleUnderscore(): void { $input = 'I_m_liuggio-b-97CA00.svg'; @@ -53,9 +47,7 @@ public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWith $this->assertEquals($assertInput, (string) $badge); } - /** - * @test - */ + #[Test] public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWithDashes(): void { $input = 'I--m--liuggio-b-97CA00.svg'; @@ -65,11 +57,8 @@ public function itShouldBeConstructedByFromURIFactoryMethodEscapingCorrectlyWith $this->assertEquals($assertInput, (string) $badge); } - /** - * @test - * - * @dataProvider positiveConversionExamples - */ + #[Test] + #[DataProvider('positiveConversionExamples')] public function itShouldValidateAvailableColorSchemes(string $colorName): void { $badge = new Badge('a', 'b', $colorName, 'flat'); diff --git a/tests/Calculator/GDTextSizeCalculatorTest.php b/tests/Calculator/GDTextSizeCalculatorTest.php index de153992..6936c610 100644 --- a/tests/Calculator/GDTextSizeCalculatorTest.php +++ b/tests/Calculator/GDTextSizeCalculatorTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests\Calculator; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Calculator\GDTextSizeCalculator; @@ -16,36 +17,28 @@ protected function setUp(): void $this->calculator = new GDTextSizeCalculator(); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize8(): void { $width = $this->calculator->calculateWidth('MIT', 8); $this->assertEquals(24.0, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize10(): void { $width = $this->calculator->calculateWidth('MIT', 10); $this->assertEquals(29.0, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize14(): void { $width = $this->calculator->calculateWidth('MIT', 14); $this->assertEquals(34.0, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithDefaultSize(): void { $width = $this->calculator->calculateWidth('MIT'); diff --git a/tests/Calculator/SvgTextSizeCalculatorTest.php b/tests/Calculator/SvgTextSizeCalculatorTest.php index 77071474..9730aab2 100644 --- a/tests/Calculator/SvgTextSizeCalculatorTest.php +++ b/tests/Calculator/SvgTextSizeCalculatorTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests\Calculator; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Calculator\SvgTextSizeCalculator; @@ -16,36 +17,28 @@ protected function setUp(): void $this->calculator = new SvgTextSizeCalculator(); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize8(): void { $width = $this->calculator->calculateWidth('MIT', 8); $this->assertEquals(24.1, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize10(): void { $width = $this->calculator->calculateWidth('MIT', 10); $this->assertEquals(27.7, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithSize14(): void { $width = $this->calculator->calculateWidth('MIT', 14); $this->assertEquals(34.8, $width); } - /** - * @test - */ + #[Test] public function itShouldComputeTextWidthWithDefaultSize(): void { $width = $this->calculator->calculateWidth('MIT'); diff --git a/tests/PoserTest.php b/tests/PoserTest.php index 884700a3..58094f1a 100644 --- a/tests/PoserTest.php +++ b/tests/PoserTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Poser; use PUGX\Poser\Render\SvgFlatRender; @@ -21,17 +22,13 @@ protected function setUp(): void ]); } - /** - * @test - */ + #[Test] public function itIsInitializable(): void { $this->assertInstanceOf(Poser::class, $this->poser); } - /** - * @test - */ + #[Test] public function itShouldBeAbleToGenerateAnSvgImage(): void { $subject = 'stable'; @@ -45,9 +42,7 @@ public function itShouldBeAbleToGenerateAnSvgImage(): void $this->assertValidSVGImageContaining((string) $image, $subject, $status); } - /** - * @test - */ + #[Test] public function itShouldBeAbleToGenerateAnSvgImageFromURI(): void { $subject = 'stable-v2.0-97CA00.svg'; @@ -57,9 +52,7 @@ public function itShouldBeAbleToGenerateAnSvgImageFromURI(): void $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - /** - * @test - */ + #[Test] public function itShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension(): void { $subject = 'stable-v2.0-97CA00'; @@ -69,9 +62,7 @@ public function itShouldBeAbleToGenerateAnSvgImageFromURIWithoutFileExtension(): $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - /** - * @test - */ + #[Test] public function itShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void { $subject = 'stable-v2.0-97CA00.svg?style=flat-square'; @@ -81,9 +72,7 @@ public function itShouldBeAbleToGenerateAnSvgImageFromURIWithStyle(): void $this->assertValidSVGImageContaining((string) $image, 'stable', 'v2.0'); } - /** - * @test - */ + #[Test] public function itThrowsExceptionWhenGeneratingAnSvgImageWithBadURI(): void { $subject = 'stable-v2.0-'; diff --git a/tests/Render/SvgFlatRenderTest.php b/tests/Render/SvgFlatRenderTest.php index 67729c83..90967814 100644 --- a/tests/Render/SvgFlatRenderTest.php +++ b/tests/Render/SvgFlatRenderTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests\Render; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Badge; use PUGX\Poser\Calculator\TextSizeCalculatorInterface; @@ -21,9 +22,7 @@ protected function setUp(): void $this->render = new SvgFlatRender($this->calculator); } - /** - * @test - */ + #[Test] public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg'); @@ -32,9 +31,7 @@ public function itShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - /** - * @test - */ + #[Test] public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void { $fixture = __DIR__ . '/../Fixtures/flat.svg'; @@ -45,9 +42,7 @@ public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void $this->assertEquals($template, (string) $image); } - /** - * @test - */ + #[Test] public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('flat', $this->render->getBadgeStyle()); diff --git a/tests/Render/SvgFlatSquareRenderTest.php b/tests/Render/SvgFlatSquareRenderTest.php index 0c53f90c..577f6b19 100644 --- a/tests/Render/SvgFlatSquareRenderTest.php +++ b/tests/Render/SvgFlatSquareRenderTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests\Render; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Badge; use PUGX\Poser\Calculator\TextSizeCalculatorInterface; @@ -21,9 +22,7 @@ protected function setUp(): void $this->render = new SvgFlatSquareRender($this->calculator); } - /** - * @test - */ + #[Test] public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg?style=flat-square'); @@ -32,9 +31,7 @@ public function itShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - /** - * @test - */ + #[Test] public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void { $fixture = __DIR__ . '/../Fixtures/flat-square.svg'; @@ -45,9 +42,7 @@ public function itShouldRenderALicenseMitExactlyLikeThisSvg(): void $this->assertEquals($template, (string) $image); } - /** - * @test - */ + #[Test] public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('flat-square', $this->render->getBadgeStyle()); diff --git a/tests/Render/SvgPlasticRenderTest.php b/tests/Render/SvgPlasticRenderTest.php index e7c5827b..4db2c9e7 100644 --- a/tests/Render/SvgPlasticRenderTest.php +++ b/tests/Render/SvgPlasticRenderTest.php @@ -4,6 +4,7 @@ namespace PUGX\Poser\Tests\Render; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use PUGX\Poser\Badge; use PUGX\Poser\Calculator\TextSizeCalculatorInterface; @@ -21,9 +22,7 @@ protected function setUp(): void $this->render = new SvgPlasticRender($this->calculator); } - /** - * @test - */ + #[Test] public function itShouldRenderASvg(): void { $badge = Badge::fromURI('version-stable-97CA00.svg?style=plastic'); @@ -32,17 +31,13 @@ public function itShouldRenderASvg(): void $this->assertValidSVGImage((string) $image); } - /** - * @test - */ + #[Test] public function itShouldReturnCorrectBadgeStyle(): void { $this->assertEquals('plastic', $this->render->getBadgeStyle()); } - /** - * @test - */ + #[Test] public function itThrowsExceptionWhenRenderingInvalidSvg(): void { $templatesDir = __DIR__ . '/../Fixtures/invalid_template'; @@ -55,9 +50,7 @@ public function itThrowsExceptionWhenRenderingInvalidSvg(): void $render->render($badge); } - /** - * @test - */ + #[Test] public function itThrowsExceptionWhenRenderingNonSvgXml(): void { $templatesDir = __DIR__ . '/../Fixtures/xml_template'; From 1b79508833d1b6ab47c5e3b192f6d7fe94119e59 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Fri, 24 Oct 2025 18:20:20 +0200 Subject: [PATCH 10/12] ci: Fix GitHub action php workflow --- .github/workflows/php.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index a5f27711..dcac38f4 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -59,10 +59,10 @@ jobs: run: docker compose run --rm ${{ matrix.container }} bin/php-cs-fixer fix --verbose --diff --dry-run - name: Unit tests - run: ./bin/phpunit + run: docker compose run --rm ${{ matrix.container }} ./bin/phpunit - name: Unit tests with coverage - run: XDEBUG_MODE=coverage ./bin/phpunit --coverage-clover coverage.xml + run: docker compose run -e XDEBUG_MODE=coverage --rm ${{ matrix.container }} ./bin/phpunit --coverage-clover coverage.xml - name: Run behat tests run: docker compose run --rm ${{ matrix.container }} ./bin/behat --snippets-for From ae5dd4a5ebcf063a97415e5f72e8c28c5f6c9e7f Mon Sep 17 00:00:00 2001 From: jmleroux Date: Fri, 24 Oct 2025 18:27:24 +0200 Subject: [PATCH 11/12] test: Fix PhpUnit configuration --- phpunit.xml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 2ae4a9aa..05ed9b38 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,18 +1,15 @@ + xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" + colors="true" failOnRisky="true" beStrictAboutOutputDuringTests="true"> tests - + src - + From f857352c8127ab19e1efb031455bea2c17968ad0 Mon Sep 17 00:00:00 2001 From: jmleroux Date: Fri, 24 Oct 2025 18:29:43 +0200 Subject: [PATCH 12/12] ci: Remove coverage tests from CI --- .github/workflows/php.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index dcac38f4..c0a04720 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -61,8 +61,5 @@ jobs: - name: Unit tests run: docker compose run --rm ${{ matrix.container }} ./bin/phpunit - - name: Unit tests with coverage - run: docker compose run -e XDEBUG_MODE=coverage --rm ${{ matrix.container }} ./bin/phpunit --coverage-clover coverage.xml - - name: Run behat tests run: docker compose run --rm ${{ matrix.container }} ./bin/behat --snippets-for