diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml new file mode 100644 index 00000000..12816968 --- /dev/null +++ b/.github/workflows/build_test.yml @@ -0,0 +1,66 @@ +name: Continuous Integration + +on: + push: + # Avoid running tests on changes to documentation + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' + +env: + COMPOSER_ARGS: '--no-progress' + +jobs: + build: + strategy: + matrix: + php_version: ['8.1', '8.2', '8.3'] + deps: ['--prefer-lowest --prefer-dist', ''] + include: + - code-coverage: 'yes' + php_version: '8.2' + deps: '' + runs-on: ubuntu-latest + + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{matrix.php_version}} + + - name: Show PHP version + run: php -v + + - uses: actions/checkout@v4 + name: Checkout branch + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php-${{ matrix.php_version }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php--${{matrix.php_version}}- + + - name: Install/update dependencies + run: composer update ${{matrix.deps}} $COMPOSER_ARGS + + - name: Run PHPUnit test suite + if: ${{ matrix.code-coverage != 'yes' }} + run: composer run-script test + + - name: Run PHPUnit test suite with coverage + if: ${{ matrix.code-coverage == 'yes' }} + run: composer run-script test-coverage + + - name: Upload coverage results to Coverall + if: ${{ matrix.code-coverage == 'yes' }} + uses: coverallsapp/github-action@v2 + + diff --git a/.gitignore b/.gitignore index f61aa87e..0c5001f1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock .php_cs.cache build .phpunit.result.cache +/.phpunit.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2162ad6b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -language: php - -cache: - directories: - - $HOME/.composer/cache - - $HOME/.php-cs-fixer - -env: - global: - - COMPOSER_ARGS="--no-interaction" - - XDEBUG_MODE=coverage - -matrix: - include: - - php: 7.3 - env: - - DEPENDENCIES="" - - php: 7.3 - env: - - DEPENDENCIES="--prefer-lowest --prefer-stable" - - php: 7.4 - env: - - DEPENDENCIES="" - - EXECUTE_CS_CHECK=true - - TEST_COVERAGE=true - - php: 7.4 - env: - - DEPENDENCIES="--prefer-lowest --prefer-stable" - - php: 8.0 - env: - - DEPENDENCIES="--prefer-lowest --prefer-stable" - - php: 8.0 - env: - - DEPENDENCIES="" -before_install: - - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0; fi - -before_script: - - mkdir -p ./build/logs - - mkdir -p "$HOME/.php-cs-fixer" - - composer self-update - - composer update $COMPOSER_ARGS $DEPENDENCIES - -script: - - if [[ $TEST_COVERAGE == 'true' ]]; then ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml; else ./vendor/bin/phpunit; fi - - if [[ $EXECUTE_CS_CHECK == 'true' ]]; then ./vendor/bin/php-cs-fixer fix -v --diff --dry-run; fi - - if [[ $EXECUTE_CS_CHECK == 'true' ]]; then ./vendor/bin/docheader check src/ tests/; fi - -after_success: - - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry php vendor/bin/php-coveralls -v; fi - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/90753b5c820315c57410 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/composer.json b/composer.json index 1d0e5d5d..fee725f5 100644 --- a/composer.json +++ b/composer.json @@ -38,15 +38,16 @@ "php": "^7.3 || ^8.0", "laminas/laminas-servicemanager": "^3.3", "laminas/laminas-stdlib": "^3.1", - "doctrine/persistence": "^2.0" + "doctrine/persistence": "^2.0 || ^3.0" }, "require-dev": { "malukenho/docheader": "^0.1.7", - "phpunit/phpunit": "^9.5.0", + "phpunit/phpunit": "^10.0", "phpspec/prophecy": "^1.10", - "friendsofphp/php-cs-fixer": "^2.9.3", - - "php-coveralls/php-coveralls": "^2.0" + "phpspec/prophecy-phpunit": "^2.0", + "friendsofphp/php-cs-fixer": "^3.43", + "php-coveralls/php-coveralls": "^2.0", + "doctrine/collections": "^2.0" }, "autoload": { "psr-4": { @@ -75,7 +76,8 @@ ], "cs": "php-cs-fixer fix -v --diff --dry-run", "cs-fix": "php-cs-fixer fix -v --diff", - "test": "phpunit", - "header": "docheader check src test" + "test": "phpunit --colors=always", + "header": "docheader check src test", + "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4752ff3a..7633616e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,15 +1,22 @@ - - - - ./src - - - - - + ./test + + + ./src + + diff --git a/test/Assertion/AssertionSetTest.php b/test/Assertion/AssertionSetTest.php index 276354e9..01bb5fe4 100644 --- a/test/Assertion/AssertionSetTest.php +++ b/test/Assertion/AssertionSetTest.php @@ -81,8 +81,13 @@ public function testWhenNoConditionIsGivenAndIsUsed() $assertionContainer = $this->getMockBuilder(AssertionContainerInterface::class)->getMock(); $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', 'barFactory']); - $assertionContainer->expects($this->at(0))->method('get')->with('fooFactory')->willReturn($fooAssertion); - $assertionContainer->expects($this->at(1))->method('get')->with('barFactory')->willReturn($barAssertion); + $matcher = $this->exactly(2); + $assertionContainer->expects($matcher) + ->method('get') + ->willReturnCallback(fn (string $key) => match ($key) { + 'fooFactory' => $fooAssertion, + 'barFactory' => $barAssertion, + }); $this->assertFalse($assertionSet->assert('permission')); @@ -98,7 +103,7 @@ public function testAndConditionWillBreakEarlyWithFailure() $assertionContainer = $this->getMockBuilder(AssertionContainerInterface::class)->getMock(); $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_AND]); - $assertionContainer->expects($this->at(0))->method('get')->with('fooFactory')->willReturn($fooAssertion); + $assertionContainer->expects($this->once())->method('get')->with('fooFactory')->willReturn($fooAssertion); $this->assertFalse($assertionSet->assert('permission')); @@ -114,7 +119,7 @@ public function testOrConditionWillBreakEarlyWithSuccess() $assertionContainer = $this->getMockBuilder(AssertionContainerInterface::class)->getMock(); $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_OR]); - $assertionContainer->expects($this->at(0))->method('get')->with('fooFactory')->willReturn($fooAssertion); + $assertionContainer->expects($this->once())->method('get')->with('fooFactory')->willReturn($fooAssertion); $this->assertTrue($assertionSet->assert('permission')); @@ -189,8 +194,12 @@ public function testUsesAssertionsAsArrays() $assertionContainer = $this->getMockBuilder(AssertionContainerInterface::class)->getMock(); $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', ['barFactory']]); - $assertionContainer->expects($this->at(0))->method('get')->with('fooFactory')->willReturn($fooAssertion); - $assertionContainer->expects($this->at(1))->method('get')->with('barFactory')->willReturn($barAssertion); + $assertionContainer->expects($this->exactly(2)) + ->method('get') + ->willReturnCallback(fn (string $key) => match ($key) { + 'fooFactory' => $fooAssertion, + 'barFactory' => $barAssertion, + }); $this->assertTrue($assertionSet->assert('permission')); @@ -235,7 +244,7 @@ private function assertionsCalled(array $assertions, array $assertionCalledCount } } - public function dpMatrix() + static public function dpMatrix(): array { return [ // no assertions will fail diff --git a/test/Container/AuthorizationServiceFactoryTest.php b/test/Container/AuthorizationServiceFactoryTest.php index d4300ac3..7af870e1 100644 --- a/test/Container/AuthorizationServiceFactoryTest.php +++ b/test/Container/AuthorizationServiceFactoryTest.php @@ -28,6 +28,7 @@ use LmcRbac\Service\AuthorizationService; use LmcRbac\Service\RoleServiceInterface; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Container\ContainerInterface; /** @@ -35,6 +36,8 @@ */ class AuthorizationServiceFactoryTest extends TestCase { + use ProphecyTrait; + public function testCanCreateAuthorizationService(): void { $container = $this->prophesize(ContainerInterface::class); diff --git a/test/Service/AuthorizationServiceTest.php b/test/Service/AuthorizationServiceTest.php index 99c37ae2..b346f614 100644 --- a/test/Service/AuthorizationServiceTest.php +++ b/test/Service/AuthorizationServiceTest.php @@ -43,7 +43,7 @@ */ class AuthorizationServiceTest extends TestCase { - public function grantedProvider(): array + static function grantedProvider(): array { return [ // Simple is granted diff --git a/test/Service/RoleServiceTest.php b/test/Service/RoleServiceTest.php index adab8d0a..1ebb29aa 100644 --- a/test/Service/RoleServiceTest.php +++ b/test/Service/RoleServiceTest.php @@ -31,12 +31,15 @@ use LmcRbacTest\Asset\Identity; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; /** * @covers \LmcRbac\Service\RoleService */ class RoleServiceTest extends TestCase { + use ProphecyTrait; + public function testReturnGuestRoleIfNoIdentityIsGiven(): void { $roleService = new RoleService(new InMemoryRoleProvider([]), 'guest');