From b2f25fbe09c80f30d94201dba95ff628ebbd61ef Mon Sep 17 00:00:00 2001 From: Contributte AI Date: Sun, 4 Jan 2026 14:43:24 +0000 Subject: [PATCH 1/5] CI: use reusable workflows, add workflow_dispatch trigger --- .github/.kodiak.toml | 10 - .github/workflows/main.yaml | 265 ++---------------- ...tainerConstraintValidatorFactoryTest.phpt} | 0 .../ValidatorExtensionTest.phpt} | 0 .../DummyConstraint.php | 0 .../DummyConstraintValidator.php | 0 6 files changed, 19 insertions(+), 256 deletions(-) delete mode 100644 .github/.kodiak.toml rename tests/{cases/ContainerConstraintValidatorFactoryTest.php => Cases/ContainerConstraintValidatorFactoryTest.phpt} (100%) rename tests/{cases/ValidatorExtensionTest.php => Cases/ValidatorExtensionTest.phpt} (100%) rename tests/{fixtures => Fixtures}/DummyConstraint.php (100%) rename tests/{fixtures => Fixtures}/DummyConstraintValidator.php (100%) diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml deleted file mode 100644 index 60c34b6..0000000 --- a/.github/.kodiak.toml +++ /dev/null @@ -1,10 +0,0 @@ -version = 1 - -[merge] -automerge_label = "automerge" -blacklist_title_regex = "^WIP.*" -blacklist_labels = ["WIP"] -method = "rebase" -delete_branch_on_merge = true -notify_on_conflict = true -optimistic_updates = false diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index d211477..141c7e9 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -6,260 +6,33 @@ on: - ".docs/**" push: branches: - - "*" + - "master" schedule: - cron: "0 8 * * 1" # At 08:00 on Monday - -env: - extensions: "json" - cache-version: "1" - composer-version: "v2" - composer-install: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable" + workflow_dispatch: jobs: qa: name: "Quality assurance" - runs-on: "${{ matrix.operating-system }}" - - strategy: - matrix: - php-version: [ "8.5" ] - operating-system: [ "ubuntu-latest" ] - fail-fast: false - - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - - name: "Setup PHP cache environment" - id: "extcache" - uses: "shivammathur/cache-extensions@v1" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - key: "${{ env.cache-version }}" - - - name: "Cache PHP extensions" - uses: "actions/cache@v4" - with: - path: "${{ steps.extcache.outputs.dir }}" - key: "${{ steps.extcache.outputs.key }}" - restore-keys: "${{ steps.extcache.outputs.key }}" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - tools: "composer:${{ env.composer-version }}, cs2pr" + uses: contributte/.github/.github/workflows/nette-tester-qa-v2.yml@master + with: + php: "8.2" - - name: "Setup problem matchers for PHP" - run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' - - - name: "Get Composer cache directory" - id: "composercache" - run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' - - - name: "Cache PHP dependencies" - uses: "actions/cache@v4" - with: - path: "${{ steps.composercache.outputs.dir }}" - key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" - restore-keys: "${{ runner.os }}-composer-" - - - name: "Validate Composer" - run: "composer validate" - - - name: "Install dependencies" - run: "${{ env.composer-install }}" - - static-analysis: + phpstan: name: "Static analysis" - runs-on: "${{ matrix.operating-system }}" - - strategy: - matrix: - php-version: [ "8.5" ] - operating-system: [ "ubuntu-latest" ] - fail-fast: false - - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - - name: "Setup PHP cache environment" - id: "extcache" - uses: "shivammathur/cache-extensions@v1" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - key: "${{ env.cache-version }}" - - - name: "Cache PHP extensions" - uses: "actions/cache@v4" - with: - path: "${{ steps.extcache.outputs.dir }}" - key: "${{ steps.extcache.outputs.key }}" - restore-keys: "${{ steps.extcache.outputs.key }}" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - tools: "composer:${{ env.composer-version }}" - - - name: "Setup problem matchers for PHP" - run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' - - - name: "Get Composer cache directory" - id: "composercache" - run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' - - - name: "Cache PHP dependencies" - uses: "actions/cache@v4" - with: - path: "${{ steps.composercache.outputs.dir }}" - key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" - restore-keys: "${{ runner.os }}-composer-" - - - name: "Install dependencies" - run: "${{ env.composer-install }}" - - - name: "PHPStan" - run: "make phpstan" + uses: contributte/.github/.github/workflows/nette-tester-phpstan-v2.yml@master + with: + php: "8.2" tests: name: "Tests" - runs-on: "${{ matrix.operating-system }}" - - strategy: - matrix: - php-version: [ "8.2", "8.3", "8.4", "8.5" ] - operating-system: [ "ubuntu-latest" ] - composer-args: [ "" ] - include: - - php-version: "8.2" - operating-system: "ubuntu-latest" - composer-args: "--prefer-lowest" - fail-fast: false - - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - - name: "Setup PHP cache environment" - id: "extcache" - uses: "shivammathur/cache-extensions@v1" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - key: "${{ env.cache-version }}" - - - name: "Cache PHP extensions" - uses: "actions/cache@v4" - with: - path: "${{ steps.extcache.outputs.dir }}" - key: "${{ steps.extcache.outputs.key }}" - restore-keys: "${{ steps.extcache.outputs.key }}" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - tools: "composer:${{ env.composer-version }}" - - - name: "Setup problem matchers for PHP" - run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' - - - name: "Get Composer cache directory" - id: "composercache" - run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' - - - name: "Cache PHP dependencies" - uses: "actions/cache@v4" - with: - path: "${{ steps.composercache.outputs.dir }}" - key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" - restore-keys: "${{ runner.os }}-composer-" - - - name: "Install dependencies" - run: "${{ env.composer-install }} ${{ matrix.composer-args }}" - - - name: "Tests" - run: "make tests" - - - name: "Upload test output" - if: ${{ failure() }} - uses: actions/upload-artifact@v4 - with: - name: output - path: tests/**/output - - tests-code-coverage: - name: "Tests with code coverage" - runs-on: "${{ matrix.operating-system }}" - - strategy: - matrix: - php-version: [ "8.5" ] - operating-system: [ "ubuntu-latest" ] - fail-fast: false - - if: "github.event_name == 'push'" - - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - - name: "Setup PHP cache environment" - id: "extcache" - uses: "shivammathur/cache-extensions@v1" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - key: "${{ env.cache-version }}" - - - name: "Cache PHP extensions" - uses: "actions/cache@v4" - with: - path: "${{ steps.extcache.outputs.dir }}" - key: "${{ steps.extcache.outputs.key }}" - restore-keys: "${{ steps.extcache.outputs.key }}" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.extensions }}" - tools: "composer:${{ env.composer-version }} " - - - name: "Setup problem matchers for PHP" - run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' - - - name: "Get Composer cache directory" - id: "composercache" - run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' - - - name: "Cache PHP dependencies" - uses: "actions/cache@v4" - with: - path: "${{ steps.composercache.outputs.dir }}" - key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" - restore-keys: "${{ runner.os }}-composer-" - - - name: "Install dependencies" - run: "${{ env.composer-install }}" - - - name: "Tests" - run: "make coverage-clover" - - - name: "Coveralls.io" - env: - CI_NAME: github - CI: true - COVERALLS_REPO_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - run: | - wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar - php php-coveralls.phar --verbose --config tests/.coveralls.yml + uses: contributte/.github/.github/workflows/nette-tester-tests-v2.yml@master + with: + matrix: "[8.2, 8.3, 8.4, 8.5]" + lowest: "8.2" + + coverage: + name: "Coverage" + uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master + with: + php: "8.2" diff --git a/tests/cases/ContainerConstraintValidatorFactoryTest.php b/tests/Cases/ContainerConstraintValidatorFactoryTest.phpt similarity index 100% rename from tests/cases/ContainerConstraintValidatorFactoryTest.php rename to tests/Cases/ContainerConstraintValidatorFactoryTest.phpt diff --git a/tests/cases/ValidatorExtensionTest.php b/tests/Cases/ValidatorExtensionTest.phpt similarity index 100% rename from tests/cases/ValidatorExtensionTest.php rename to tests/Cases/ValidatorExtensionTest.phpt diff --git a/tests/fixtures/DummyConstraint.php b/tests/Fixtures/DummyConstraint.php similarity index 100% rename from tests/fixtures/DummyConstraint.php rename to tests/Fixtures/DummyConstraint.php diff --git a/tests/fixtures/DummyConstraintValidator.php b/tests/Fixtures/DummyConstraintValidator.php similarity index 100% rename from tests/fixtures/DummyConstraintValidator.php rename to tests/Fixtures/DummyConstraintValidator.php From 4f71424f6ebe1c08c003e9d77a9fa30ec8251ba4 Mon Sep 17 00:00:00 2001 From: Contributte AI Date: Sun, 4 Jan 2026 14:43:33 +0000 Subject: [PATCH 2/5] Tests: use contributte/tester, rename to .phpt extension --- tests/.coveralls.yml | 4 - tests/.gitignore | 10 - ...ntainerConstraintValidatorFactoryTest.phpt | 97 +++-- tests/Cases/ValidatorExtensionTest.phpt | 350 +++++++++--------- tests/Fixtures/DummyConstraintValidator.php | 9 +- tests/bootstrap.php | 4 +- 6 files changed, 218 insertions(+), 256 deletions(-) delete mode 100644 tests/.coveralls.yml delete mode 100644 tests/.gitignore diff --git a/tests/.coveralls.yml b/tests/.coveralls.yml deleted file mode 100644 index 82764a3..0000000 --- a/tests/.coveralls.yml +++ /dev/null @@ -1,4 +0,0 @@ -# for php-coveralls -service_name: travis-ci -coverage_clover: coverage.xml -json_path: coverage.json diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index f0d3402..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Folders - recursive -*.expected -*.actual - -# Folders -/tmp - -# Files -/*.log -/*.html diff --git a/tests/Cases/ContainerConstraintValidatorFactoryTest.phpt b/tests/Cases/ContainerConstraintValidatorFactoryTest.phpt index cc8b3c7..f00729b 100644 --- a/tests/Cases/ContainerConstraintValidatorFactoryTest.phpt +++ b/tests/Cases/ContainerConstraintValidatorFactoryTest.phpt @@ -2,76 +2,65 @@ namespace Tests\Cases; +use Contributte\Tester\Environment; +use Contributte\Tester\Toolkit; use Contributte\Validator\ContainerConstraintValidatorFactory; use Nette\DI\Compiler; use Nette\DI\ContainerLoader; use stdClass; use Tester\Assert; -use Tester\TestCase; use Tests\Fixtures\DummyConstraint; use Tests\Fixtures\DummyConstraintValidator; require __DIR__ . '/../bootstrap.php'; -/** - * @testCase - */ -final class ContainerConstraintValidatorFactoryTest extends TestCase -{ - - public function testGetFromContainer(): void - { - $loader = new ContainerLoader(__DIR__ . '/../tmp/nette.configurator', true); - $containerClass = $loader->load(static function (Compiler $compiler): void { - $compiler->addConfig([ - 'services' => [ - 'dependency' => [ - 'type' => stdClass::class, - 'imported' => true, - ], - [ - 'factory' => DummyConstraintValidator::class, - ], +Toolkit::test(function (): void { + $loader = new ContainerLoader(Environment::getTestDir(), true); + $containerClass = $loader->load(static function (Compiler $compiler): void { + $compiler->addConfig([ + 'services' => [ + 'dependency' => [ + 'type' => stdClass::class, + 'imported' => true, + ], + [ + 'factory' => DummyConstraintValidator::class, ], - ]); - }); + ], + ]); + }); - $container = new $containerClass(); + $container = new $containerClass(); - $expectedDependency = new stdClass(); - $container->addService('dependency', $expectedDependency); + $expectedDependency = new stdClass(); + $container->addService('dependency', $expectedDependency); - $factory = new ContainerConstraintValidatorFactory($container); - $constraintValidator = $factory->getInstance(new DummyConstraint()); - Assert::type(DummyConstraintValidator::class, $constraintValidator); - Assert::same($expectedDependency, $constraintValidator->dependency); - } + $factory = new ContainerConstraintValidatorFactory($container); + $constraintValidator = $factory->getInstance(new DummyConstraint()); + Assert::type(DummyConstraintValidator::class, $constraintValidator); + Assert::same($expectedDependency, $constraintValidator->dependency); +}); - public function testCreateInstanceViaContainer(): void - { - $loader = new ContainerLoader(__DIR__ . '/../tmp/nette.configurator', true); - $containerClass = $loader->load(static function (Compiler $compiler): void { - $compiler->addConfig([ - 'services' => [ - 'dependency' => [ - 'type' => stdClass::class, - 'imported' => true, - ], +Toolkit::test(function (): void { + $loader = new ContainerLoader(Environment::getTestDir(), true); + $containerClass = $loader->load(static function (Compiler $compiler): void { + $compiler->addConfig([ + 'services' => [ + 'dependency' => [ + 'type' => stdClass::class, + 'imported' => true, ], - ]); - }); - - $container = new $containerClass(); - - $expectedDependency = new stdClass(); - $container->addService('dependency', $expectedDependency); + ], + ]); + }, 'createInstance'); - $factory = new ContainerConstraintValidatorFactory($container); - $constraintValidator = $factory->getInstance(new DummyConstraint()); - Assert::type(DummyConstraintValidator::class, $constraintValidator); - Assert::same($expectedDependency, $constraintValidator->dependency); - } + $container = new $containerClass(); -} + $expectedDependency = new stdClass(); + $container->addService('dependency', $expectedDependency); -(new ContainerConstraintValidatorFactoryTest())->run(); + $factory = new ContainerConstraintValidatorFactory($container); + $constraintValidator = $factory->getInstance(new DummyConstraint()); + Assert::type(DummyConstraintValidator::class, $constraintValidator); + Assert::same($expectedDependency, $constraintValidator->dependency); +}); diff --git a/tests/Cases/ValidatorExtensionTest.phpt b/tests/Cases/ValidatorExtensionTest.phpt index ac7c413..c8c732c 100644 --- a/tests/Cases/ValidatorExtensionTest.phpt +++ b/tests/Cases/ValidatorExtensionTest.phpt @@ -3,8 +3,9 @@ namespace Tests\Cases; use Closure; +use Contributte\Tester\Environment; +use Contributte\Tester\Toolkit; use Contributte\Validator\DI\ValidatorExtension; -use Doctrine\Common\Annotations\Reader; use Nette\DI\Compiler; use Nette\DI\Container; use Nette\DI\ContainerLoader; @@ -18,194 +19,183 @@ use Symfony\Component\Translation\Translator; use Symfony\Component\Validator\Mapping\Loader\LoaderChain; use Symfony\Component\Validator\Validator\ValidatorInterface; use Tester\Assert; -use Tester\TestCase; require __DIR__ . '/../bootstrap.php'; /** - * @testCase + * @param mixed[] $config */ -final class ValidatorExtensionTest extends TestCase +function createContainer(array $config, ?string $key = null): Container { + $tempDir = Environment::getTestDir(); + $loader = new ContainerLoader($tempDir, true); - public function testCreateValidator(): void - { - $container = $this->createContainer([], __METHOD__); + $containerClass = $loader->load(static function (Compiler $compiler) use ($tempDir, $config): void { + $compiler->addExtension('validator', new ValidatorExtension()); + $compiler->addConfig(['parameters' => ['tempDir' => $tempDir], 'validator' => $config]); + $compiler->addConfig(['services' => [new Statement(Translator::class, ['en'])]]); + }, $key); - $validator = $container->getByType(ValidatorInterface::class); - Assert::type(ValidatorInterface::class, $validator); - } + return new $containerClass(); +} - public function testAttributesMapping(): void - { - $container = $this->createContainer([ - 'mapping' => [ - 'attributes' => true, - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'enableAttributeMapping', static function ($value): void { - Assert::true($value); - }); - } - - public function testXmlMapping(): void - { - $container = $this->createContainer([ - 'mapping' => [ - 'xml' => [ - __DIR__ . '/validator.xml', - ], - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'xmlMappings', static function ($value): void { - Assert::same([__DIR__ . '/validator.xml'], $value); - }); - } - - public function testYamlMapping(): void - { - $container = $this->createContainer([ - 'mapping' => [ - 'yaml' => [ - __DIR__ . '/validator.yml', - ], - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'yamlMappings', static function ($value): void { - Assert::same([__DIR__ . '/validator.yml'], $value); - }); - } - - public function testMethodMapping(): void - { - $container = $this->createContainer([ - 'mapping' => [ - 'methods' => [ - 'provideConstraints', - ], - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'methodMappings', static function ($value): void { - Assert::same(['provideConstraints'], $value); - }); - } - - public function testLoaders(): void - { - $container = $this->createContainer([ - 'loaders' => [ - new Statement(LoaderChain::class, [[]]), - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'loaders', static function ($value): void { - Assert::type('list', $value); - Assert::type(LoaderChain::class, $value[0]); - }); - } - - public function testDefaultCache(): void - { - $container = $this->createContainer([], __METHOD__); - $this->assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { - Assert::type(FilesystemAdapter::class, $value); - }); - } - - public function testCustomCache(): void - { - $container = $this->createContainer([ - 'cache' => new Statement(NullAdapter::class), - ], __METHOD__); - $this->assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { - Assert::type(NullAdapter::class, $value); - }); - } - - public function testDisableCache(): void - { - $container = $this->createContainer(['cache' => null], __METHOD__); - $this->assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { - Assert::type(ArrayAdapter::class, $value); - }); - } - - public function testNoTranslator(): void - { - $container = $this->createContainer([ - 'translation' => [ - 'translator' => false, - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'translator', static function ($value): void { - Assert::null($value); - }); - } - - public function testAutowiredTranslator(): void - { - $container = $this->createContainer([ - 'translation' => [ - 'domain' => 'validation', - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'translator', static function ($value): void { - Assert::type(Translator::class, $value); - }); - $this->assertValidatorBuilderProperty($container, 'translationDomain', static function ($value): void { - Assert::same('validation', $value); - }); - } - - public function testSpecificTranslator(): void - { - $container = $this->createContainer([ - 'translation' => [ - 'translator' => new Statement(IdentityTranslator::class), - ], - ], __METHOD__); - - $this->assertValidatorBuilderProperty($container, 'translator', static function ($value): void { - Assert::type(IdentityTranslator::class, $value); - }); - } - - private function assertValidatorBuilderProperty( - Container $container, - string $propertyName, - Closure $assertion - ): void - { - $validatorBuilder = $container->getService('validator.validatorBuilder'); - $property = new ReflectionProperty($validatorBuilder, $propertyName); - $value = $property->getValue($validatorBuilder); - - $assertion($value); - } - - /** - * @param mixed[] $config - */ - private function createContainer(array $config, ?string $key = null): Container - { - $tempDir = __DIR__ . '/../tmp/cache/nette.configurator'; - $loader = new ContainerLoader($tempDir, true); - - $containerClass = $loader->load(static function (Compiler $compiler) use ($tempDir, $config): void { - $compiler->addExtension('validator', new ValidatorExtension()); - $compiler->addConfig(['parameters' => ['tempDir' => $tempDir], 'validator' => $config]); - $compiler->addConfig(['services' => [new Statement(Translator::class, ['en'])]]); - }, $key); - - return new $containerClass(); - } +function assertValidatorBuilderProperty( + Container $container, + string $propertyName, + Closure $assertion +): void +{ + $validatorBuilder = $container->getService('validator.validatorBuilder'); + $property = new ReflectionProperty($validatorBuilder, $propertyName); + $value = $property->getValue($validatorBuilder); + $assertion($value); } -(new ValidatorExtensionTest())->run(); +// testCreateValidator +Toolkit::test(function (): void { + $container = createContainer([], 'testCreateValidator'); + + $validator = $container->getByType(ValidatorInterface::class); + Assert::type(ValidatorInterface::class, $validator); +}); + +// testAttributesMapping +Toolkit::test(function (): void { + $container = createContainer([ + 'mapping' => [ + 'attributes' => true, + ], + ], 'testAttributesMapping'); + + assertValidatorBuilderProperty($container, 'enableAttributeMapping', static function ($value): void { + Assert::true($value); + }); +}); + +// testXmlMapping +Toolkit::test(function (): void { + $container = createContainer([ + 'mapping' => [ + 'xml' => [ + __DIR__ . '/validator.xml', + ], + ], + ], 'testXmlMapping'); + + assertValidatorBuilderProperty($container, 'xmlMappings', static function ($value): void { + Assert::same([__DIR__ . '/validator.xml'], $value); + }); +}); + +// testYamlMapping +Toolkit::test(function (): void { + $container = createContainer([ + 'mapping' => [ + 'yaml' => [ + __DIR__ . '/validator.yml', + ], + ], + ], 'testYamlMapping'); + + assertValidatorBuilderProperty($container, 'yamlMappings', static function ($value): void { + Assert::same([__DIR__ . '/validator.yml'], $value); + }); +}); + +// testMethodMapping +Toolkit::test(function (): void { + $container = createContainer([ + 'mapping' => [ + 'methods' => [ + 'provideConstraints', + ], + ], + ], 'testMethodMapping'); + + assertValidatorBuilderProperty($container, 'methodMappings', static function ($value): void { + Assert::same(['provideConstraints'], $value); + }); +}); + +// testLoaders +Toolkit::test(function (): void { + $container = createContainer([ + 'loaders' => [ + new Statement(LoaderChain::class, [[]]), + ], + ], 'testLoaders'); + + assertValidatorBuilderProperty($container, 'loaders', static function ($value): void { + Assert::type('list', $value); + Assert::type(LoaderChain::class, $value[0]); + }); +}); + +// testDefaultCache +Toolkit::test(function (): void { + $container = createContainer([], 'testDefaultCache'); + assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { + Assert::type(FilesystemAdapter::class, $value); + }); +}); + +// testCustomCache +Toolkit::test(function (): void { + $container = createContainer([ + 'cache' => new Statement(NullAdapter::class), + ], 'testCustomCache'); + assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { + Assert::type(NullAdapter::class, $value); + }); +}); + +// testDisableCache +Toolkit::test(function (): void { + $container = createContainer(['cache' => null], 'testDisableCache'); + assertValidatorBuilderProperty($container, 'mappingCache', static function ($value): void { + Assert::type(ArrayAdapter::class, $value); + }); +}); + +// testNoTranslator +Toolkit::test(function (): void { + $container = createContainer([ + 'translation' => [ + 'translator' => false, + ], + ], 'testNoTranslator'); + + assertValidatorBuilderProperty($container, 'translator', static function ($value): void { + Assert::null($value); + }); +}); + +// testAutowiredTranslator +Toolkit::test(function (): void { + $container = createContainer([ + 'translation' => [ + 'domain' => 'validation', + ], + ], 'testAutowiredTranslator'); + + assertValidatorBuilderProperty($container, 'translator', static function ($value): void { + Assert::type(Translator::class, $value); + }); + assertValidatorBuilderProperty($container, 'translationDomain', static function ($value): void { + Assert::same('validation', $value); + }); +}); + +// testSpecificTranslator +Toolkit::test(function (): void { + $container = createContainer([ + 'translation' => [ + 'translator' => new Statement(IdentityTranslator::class), + ], + ], 'testSpecificTranslator'); + + assertValidatorBuilderProperty($container, 'translator', static function ($value): void { + Assert::type(IdentityTranslator::class, $value); + }); +}); diff --git a/tests/Fixtures/DummyConstraintValidator.php b/tests/Fixtures/DummyConstraintValidator.php index c522dc7..367419c 100644 --- a/tests/Fixtures/DummyConstraintValidator.php +++ b/tests/Fixtures/DummyConstraintValidator.php @@ -9,19 +9,16 @@ final class DummyConstraintValidator extends ConstraintValidator { - /** @var stdClass */ - public $dependency; + public stdClass $dependency; public function __construct(stdClass $dependency) { $this->dependency = $dependency; } - /** - * @param mixed $value - */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { + // Dummy implementation for testing purposes } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index aff90df..86c92a0 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,9 +1,9 @@ Date: Sun, 4 Jan 2026 14:43:41 +0000 Subject: [PATCH 3/5] Config: update to contributte standards, use PHP 8.2 base --- .editorconfig | 4 +-- .gitattributes | 4 +-- .gitignore | 16 +++++----- Makefile | 34 +++++++++++++------- phpstan.neon | 35 ++++++++++++++++++--- ruleset.xml | 11 +++---- src/ContainerConstraintValidatorFactory.php | 3 +- src/DI/ValidatorExtension.php | 1 - 8 files changed, 68 insertions(+), 40 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3faf149..352f1e9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,3 @@ -# EditorConfig is awesome: http://EditorConfig.org - root = true [*] @@ -11,6 +9,6 @@ indent_style = tab indent_size = tab tab_width = 4 -[{*.json, *.yaml, *.yml, *.md}] +[*.{json,yaml,yml,md}] indent_style = space indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 12910b6..7c7fa3f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,9 @@ -# Not archived .docs export-ignore tests export-ignore .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore -.travis.yml export-ignore +.github export-ignore Makefile export-ignore phpstan.neon export-ignore -README.md export-ignore ruleset.xml export-ignore diff --git a/.gitignore b/.gitignore index 35fa452..2e26fc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,9 @@ -# IDE -.idea - - -# Composer +/.idea /vendor /composer.lock - -# Tests -/temp -/coverage.xml +/tests/tmp +/coverage.* +/tests/**/*.log +/tests/**/*.html +/tests/**/*.expected +/tests/**/*.actual diff --git a/Makefile b/Makefile index efd1247..3471684 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,34 @@ -.PHONY: install qa cs csf phpstan tests coverage-clover coverage-html - +.PHONY: install install: composer update +.PHONY: qa qa: phpstan cs +.PHONY: cs cs: - vendor/bin/codesniffer src tests +ifdef GITHUB_ACTION + vendor/bin/codesniffer --extensions="php,phpt" src tests +else + vendor/bin/codesniffer --extensions="php,phpt" src tests +endif +.PHONY: csf csf: - vendor/bin/codefixer src tests + vendor/bin/codefixer --extensions="php,phpt" src tests +.PHONY: phpstan phpstan: - vendor/bin/phpstan analyse -l max -c phpstan.neon src + vendor/bin/phpstan analyse -c phpstan.neon +.PHONY: tests tests: - vendor/bin/tester -s -p php --colors 1 -C tests/cases - -coverage-clover: - vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage ./coverage.xml --coverage-src ./src tests/cases - -coverage-html: - vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage ./coverage.html --coverage-src ./src tests/cases + vendor/bin/tester -s -p php --colors 1 -C tests/Cases + +.PHONY: coverage +coverage: +ifdef GITHUB_ACTION + vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage ./coverage.xml --coverage-src ./src tests/Cases +else + vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage ./coverage.html --coverage-src ./src tests/Cases +endif diff --git a/phpstan.neon b/phpstan.neon index 9e9adeb..c158a28 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,32 @@ includes: - - vendor/phpstan/phpstan-deprecation-rules/rules.neon - - vendor/phpstan/phpstan-nette/extension.neon - - vendor/phpstan/phpstan-nette/rules.neon - - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/contributte/phpstan/phpstan.neon + +parameters: + level: max + phpVersion: 80200 + + scanDirectories: + - src + + fileExtensions: + - php + + paths: + - src + + ignoreErrors: + # Legacy code - container methods return mixed/object types + - + identifier: assign.propertyType + path: src/ContainerConstraintValidatorFactory.php + + # Legacy code - Nette Schema returns stdClass with dynamic properties + - + identifier: property.nonObject + path: src/DI/ValidatorExtension.php + - + identifier: binaryOp.invalid + path: src/DI/ValidatorExtension.php + - + identifier: foreach.nonIterable + path: src/DI/ValidatorExtension.php diff --git a/ruleset.xml b/ruleset.xml index 93c12a5..2681d24 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,16 +1,15 @@ - + - + + + + diff --git a/src/ContainerConstraintValidatorFactory.php b/src/ContainerConstraintValidatorFactory.php index 1e82fc6..5c0f141 100644 --- a/src/ContainerConstraintValidatorFactory.php +++ b/src/ContainerConstraintValidatorFactory.php @@ -10,7 +10,6 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\ValidatorException; use function class_exists; -use function get_class; use function sprintf; final class ContainerConstraintValidatorFactory implements ConstraintValidatorFactoryInterface @@ -47,7 +46,7 @@ public function getInstance(Constraint $constraint): ConstraintValidatorInterfac } else { if (!class_exists($name)) { - throw new ValidatorException(sprintf('Constraint validator "%s" does not exist or is not enabled. Check the "validatedBy" method in your constraint class "%s".', $name, get_class($constraint))); + throw new ValidatorException(sprintf('Constraint validator "%s" does not exist or is not enabled. Check the "validatedBy" method in your constraint class "%s".', $name, $constraint::class)); } $this->validators[$name] = $this->container->createInstance($name); diff --git a/src/DI/ValidatorExtension.php b/src/DI/ValidatorExtension.php index 1aeabc4..daa4381 100644 --- a/src/DI/ValidatorExtension.php +++ b/src/DI/ValidatorExtension.php @@ -64,7 +64,6 @@ public function loadConfiguration(): void ->setFactory([$validatorBuilder, 'getValidator']); } - public function beforeCompile(): void { $validatorBuilder = $this->getContainerBuilder()->getDefinition($this->prefix('validatorBuilder')); From 328bb206536748241664a118a84d8a434183cfd5 Mon Sep 17 00:00:00 2001 From: Contributte AI Date: Sun, 4 Jan 2026 14:43:48 +0000 Subject: [PATCH 4/5] Composer: use contributte packages, update autoload-dev --- composer.json | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 8ae47fd..d5f9760 100644 --- a/composer.json +++ b/composer.json @@ -19,21 +19,17 @@ "require": { "php": ">=8.2", "nette/di": "^3.0.9", - "symfony/cache": "^6.0 || ^7.0 || ^8.0", - "symfony/config": "^6.0 || ^7.0 || ^8.0", - "symfony/validator": "^6.4 || ^7.0 || ^8.0" + "symfony/cache": "^6.0.0 || ^7.0.0 || ^8.0.0", + "symfony/config": "^6.0.0 || ^7.0.0 || ^8.0.0", + "symfony/validator": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "require-dev": { - "doctrine/cache": "^2.2", - "nette/bootstrap": "^3.0", - "nette/tester": "^2.4", - "ninjify/nunjuck": "^0.4.0", - "ninjify/qa": "^0.13.0", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-nette": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "symfony/translation": "^6.0 || ^7.0 || ^8.0" + "contributte/phpstan": "^0.2.0", + "contributte/qa": "^0.5.0", + "contributte/tester": "^0.4.0", + "doctrine/cache": "^2.2.0", + "nette/bootstrap": "^3.0.0", + "symfony/translation": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "autoload": { "psr-4": { @@ -42,7 +38,7 @@ }, "autoload-dev": { "psr-4": { - "Tests\\Fixtures\\": "tests/fixtures" + "Tests\\": "tests" } }, "minimum-stability": "dev", From 931bb51131764b1b9ec80512332c18913f76a880 Mon Sep 17 00:00:00 2001 From: Contributte AI Date: Sun, 4 Jan 2026 17:22:50 +0000 Subject: [PATCH 5/5] CI: use separate workflow files per template --- .github/workflows/codesniffer.yml | 18 +++++++++++++ .github/workflows/coverage.yml | 18 +++++++++++++ .github/workflows/main.yaml | 38 --------------------------- .github/workflows/phpstan.yml | 18 +++++++++++++ .github/workflows/tests.yml | 43 +++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/codesniffer.yml create mode 100644 .github/workflows/coverage.yml delete mode 100644 .github/workflows/main.yaml create mode 100644 .github/workflows/phpstan.yml create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/codesniffer.yml b/.github/workflows/codesniffer.yml new file mode 100644 index 0000000..a58ac4f --- /dev/null +++ b/.github/workflows/codesniffer.yml @@ -0,0 +1,18 @@ +name: "Codesniffer" + +on: + pull_request: + workflow_dispatch: + + push: + branches: ["*"] + + schedule: + - cron: "0 8 * * 1" + +jobs: + codesniffer: + name: "Codesniffer" + uses: contributte/.github/.github/workflows/codesniffer.yml@master + with: + php: "8.2" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..fac01f8 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,18 @@ +name: "Coverage" + +on: + pull_request: + workflow_dispatch: + + push: + branches: ["*"] + + schedule: + - cron: "0 9 * * 1" + +jobs: + coverage: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master + with: + php: "8.2" diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml deleted file mode 100644 index 141c7e9..0000000 --- a/.github/workflows/main.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: "build" - -on: - pull_request: - paths-ignore: - - ".docs/**" - push: - branches: - - "master" - schedule: - - cron: "0 8 * * 1" # At 08:00 on Monday - workflow_dispatch: - -jobs: - qa: - name: "Quality assurance" - uses: contributte/.github/.github/workflows/nette-tester-qa-v2.yml@master - with: - php: "8.2" - - phpstan: - name: "Static analysis" - uses: contributte/.github/.github/workflows/nette-tester-phpstan-v2.yml@master - with: - php: "8.2" - - tests: - name: "Tests" - uses: contributte/.github/.github/workflows/nette-tester-tests-v2.yml@master - with: - matrix: "[8.2, 8.3, 8.4, 8.5]" - lowest: "8.2" - - coverage: - name: "Coverage" - uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master - with: - php: "8.2" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..13ceb07 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,18 @@ +name: "Phpstan" + +on: + pull_request: + workflow_dispatch: + + push: + branches: ["*"] + + schedule: + - cron: "0 10 * * 1" + +jobs: + phpstan: + name: "Phpstan" + uses: contributte/.github/.github/workflows/phpstan.yml@master + with: + php: "8.2" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..96bcc1e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,43 @@ +name: "Nette Tester" + +on: + pull_request: + workflow_dispatch: + + push: + branches: ["*"] + + schedule: + - cron: "0 10 * * 1" + +jobs: + test85: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.5" + + test84: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.4" + + test83: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.3" + + test82: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.2" + + testlowest: + name: "Nette Tester" + uses: contributte/.github/.github/workflows/nette-tester.yml@master + with: + php: "8.2" + composer: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable --prefer-lowest"