diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7382012..3bdb8f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,13 +11,13 @@ jobs: VUFIND_LOCAL_DIR: $GITHUB_WORKSPACE/local strategy: matrix: - php-version: ['8.0', '8.1', '8.2'] + php-version: ['8.1', '8.2', '8.3'] include: - - php-version: 8.0 - phing_tasks: "phpunitfast" - php-version: 8.1 phing_tasks: "phpunitfast" - php-version: 8.2 + phing_tasks: "phpunitfast" + - php-version: 8.3 phing_tasks: "phpunitfast phpcs-console php-cs-fixer-dryrun phpstan-console" steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4591cc4..61bb5b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file, in reverse ### Changed -- The minimum PHP version requirement has been raised to 8.0. +- The minimum PHP version requirement has been raised to 8.1. ### Deprecated diff --git a/composer.json b/composer.json index 63faad7..97e9fff 100644 --- a/composer.json +++ b/composer.json @@ -15,26 +15,27 @@ }, "config": { "platform": { - "php": "8.0" + "php": "8.1" } }, "require": { - "php": ">=8.0", + "php": ">=8.1", "laminas/laminas-http": ">=2.2", "symfony/console": "^5.3||^6||^7" }, "require-dev": { - "friendsofphp/php-cs-fixer": "3.26.1", - "pear/http_request2": "2.5.1", - "phpmd/phpmd": "2.13.0", - "phpstan/phpstan": "1.10.34", - "phpunit/phpunit": "9.6.12", + "friendsofphp/php-cs-fixer": "3.51.0", + "pear/http_request2": "2.6.0", + "phpmd/phpmd": "2.15.0", + "phpstan/phpstan": "1.10.59", + "phpunit/phpunit": "10.5.11", "phing/phing": "2.17.4", - "squizlabs/php_codesniffer": "3.7.2" + "squizlabs/php_codesniffer": "3.9.0" }, "autoload": { "psr-4": { - "VuFindHarvest\\": "src/" + "VuFindHarvest\\": "src/", + "VuFindTest\\Feature\\": "tests/unit-tests/src/VuFindTest/Feature/" } } } diff --git a/phpunit.xml b/phpunit.xml index 9c13c0d..cd9d404 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,10 +1,9 @@ - - - - src - - + tests/integration-tests @@ -16,4 +15,9 @@ . + + + src + + diff --git a/tests/unit-tests/src/VuFindTest/Feature/WithConsecutiveTrait.php b/tests/unit-tests/src/VuFindTest/Feature/WithConsecutiveTrait.php new file mode 100644 index 0000000..8132758 --- /dev/null +++ b/tests/unit-tests/src/VuFindTest/Feature/WithConsecutiveTrait.php @@ -0,0 +1,86 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:testing:unit_tests Wiki + */ + +namespace VuFindTest\Feature; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Builder\InvocationStubber; +use PHPUnit\Framework\MockObject\MockObject; + +use function count; +use function func_get_args; +use function is_array; + +/** + * Trait for setting consecutive test expectations. + * + * @category VuFind + * @package Tests + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:testing:unit_tests Wiki + */ +trait WithConsecutiveTrait +{ + /** + * Expect consecutive calls to a mock. + * + * @param MockObject $mock Mock object + * @param string $method Method expecting calls + * @param array $expectedCalls Expected input parameters + * @param mixed $returnValues Return values to mock (either an array indexed parallel to + * $expectedCalls to return different values, or a single value to always return the same thing) + * + * @return InvocationStubber + */ + protected function expectConsecutiveCalls( + MockObject $mock, + string $method, + array $expectedCalls, + mixed $returnValues = null + ): InvocationStubber { + $matcher = $this->exactly(count($expectedCalls)); + $callback = function () use ($matcher, $expectedCalls, $returnValues) { + $index = $matcher->numberOfInvocations() - 1; + $expectedArgs = $expectedCalls[$index] ?? []; + $actualArgs = func_get_args(); + foreach ($expectedArgs as $i => $expected) { + if ($expected instanceof Constraint) { + $expected->evaluate($actualArgs[$i] ?? null); + } else { + $this->assertEquals($expected, $actualArgs[$i] ?? null); + } + } + return is_array($returnValues) ? $returnValues[$index] ?? null : $returnValues; + }; + return $mock->expects($matcher) + ->method($method) + ->willReturnCallback($callback); + } +} diff --git a/tests/unit-tests/src/VuFindTest/OaiPmh/HarvesterTest.php b/tests/unit-tests/src/VuFindTest/OaiPmh/HarvesterTest.php index 447dc7b..7b608f7 100644 --- a/tests/unit-tests/src/VuFindTest/OaiPmh/HarvesterTest.php +++ b/tests/unit-tests/src/VuFindTest/OaiPmh/HarvesterTest.php @@ -42,6 +42,8 @@ */ class HarvesterTest extends \PHPUnit\Framework\TestCase { + use \VuFindTest\Feature\WithConsecutiveTrait; + /** * Time zone setting used with setup/tearDown * @@ -210,15 +212,18 @@ public function testSimpleListRecords() { $comm = $this->getMockCommunicator(); $expectedSettings = ['metadataPrefix' => 'oai_dc']; - $comm->expects($this->exactly(2))->method('request') - ->withConsecutive( + $this->expectConsecutiveCalls( + $comm, + 'request', + [ ['Identify', []], ['ListRecords', $expectedSettings], - ) - ->willReturnOnConsecutiveCalls( + ], + [ simplexml_load_string($this->getFakeIdentifyResponse()), - simplexml_load_string($this->getFakeResponse()) - ); + simplexml_load_string($this->getFakeResponse()), + ] + ); $writer = $this->getMockRecordWriter(); $writer->expects($this->once())->method('write') ->with($this->isInstanceOf('SimpleXMLElement')) @@ -248,15 +253,18 @@ public function testListRecordsWithResumption() 'from' => '2016-07-01', 'until' => '2016-07-31', ]; $expectedSettings1 = ['resumptionToken' => 'more']; - $comm->expects($this->exactly(2))->method('request') - ->withConsecutive( + $this->expectConsecutiveCalls( + $comm, + 'request', + [ ['ListRecords', $expectedSettings0], ['ListRecords', $expectedSettings1], - ) - ->willReturnOnConsecutiveCalls( + ], + [ simplexml_load_string($this->getFakeResponseWithToken()), - simplexml_load_string($this->getFakeResponse()) - ); + simplexml_load_string($this->getFakeResponse()), + ] + ); $writer = $this->getMockRecordWriter(); $writer->expects($this->exactly(2))->method('write') ->with($this->isInstanceOf('SimpleXMLElement')); @@ -290,12 +298,8 @@ public function testListRecordsWithStopAfterOption() 'from' => '2016-07-01', 'until' => '2016-07-31', ]; $comm->expects($this->exactly(1))->method('request') - ->withConsecutive( - ['ListRecords', $expectedSettings0], - ) - ->willReturnOnConsecutiveCalls( - simplexml_load_string($this->getFakeResponse()) - ); + ->with('ListRecords', $expectedSettings0) + ->willReturn(simplexml_load_string($this->getFakeResponse())); $writer = $this->getMockRecordWriter(); $writer->expects($this->exactly(1))->method('write') ->with($this->isInstanceOf('SimpleXMLElement')); @@ -327,15 +331,18 @@ public function testBadResumptionToken() $comm = $this->getMockCommunicator(); $expectedSettings = ['resumptionToken' => 'foo']; - $comm->expects($this->exactly(2))->method('request') - ->withConsecutive( + $this->expectConsecutiveCalls( + $comm, + 'request', + [ ['Identify', []], ['ListRecords', $expectedSettings], - ) - ->willReturnOnConsecutiveCalls( + ], + [ simplexml_load_string($this->getFakeIdentifyResponse()), - simplexml_load_string($this->getTokenErrorResponse()) - ); + simplexml_load_string($this->getTokenErrorResponse()), + ] + ); $sm = $this->getMockStateManager(); $sm->expects($this->any())->method('loadState') ->will($this->returnValue([null, 'foo', 'bar', 'baz'])); @@ -361,15 +368,18 @@ public function testArbitraryOaiError() $comm = $this->getMockCommunicator(); $expectedSettings = ['metadataPrefix' => 'oai_dc']; - $comm->expects($this->exactly(2))->method('request') - ->withConsecutive( + $this->expectConsecutiveCalls( + $comm, + 'request', + [ ['Identify', []], ['ListRecords', $expectedSettings], - ) - ->willReturnOnConsecutiveCalls( + ], + [ simplexml_load_string($this->getFakeIdentifyResponse()), - simplexml_load_string($this->getArbitraryErrorResponse()) - ); + simplexml_load_string($this->getArbitraryErrorResponse()), + ] + ); $harvester = $this->getHarvester( ['dateGranularity' => 'YYYY-MM-DDThh:mm:ssZ'], $comm @@ -387,15 +397,18 @@ public function testSimpleListRecordsGranularityHandling() { $comm = $this->getMockCommunicator(); $expectedSettings = ['metadataPrefix' => 'oai_dc']; - $comm->expects($this->exactly(2))->method('request') - ->withConsecutive( + $this->expectConsecutiveCalls( + $comm, + 'request', + [ ['Identify', []], ['ListRecords', $expectedSettings], - ) - ->willReturnOnConsecutiveCalls( + ], + [ simplexml_load_string($this->getFakeIdentifyResponse()), - simplexml_load_string($this->getFakeResponse()) - ); + simplexml_load_string($this->getFakeResponse()), + ] + ); $writer = $this->getMockRecordWriter(); $writer->expects($this->once())->method('write') ->with($this->isInstanceOf('SimpleXMLElement')) diff --git a/tests/unit-tests/src/VuFindTest/RecordWriterStrategy/IndividualRecordWriterStrategyTest.php b/tests/unit-tests/src/VuFindTest/RecordWriterStrategy/IndividualRecordWriterStrategyTest.php index 7d7632e..7b8d07d 100644 --- a/tests/unit-tests/src/VuFindTest/RecordWriterStrategy/IndividualRecordWriterStrategyTest.php +++ b/tests/unit-tests/src/VuFindTest/RecordWriterStrategy/IndividualRecordWriterStrategyTest.php @@ -40,6 +40,8 @@ */ class IndividualRecordWriterStrategyTest extends \PHPUnit\Framework\TestCase { + use \VuFindTest\Feature\WithConsecutiveTrait; + /** * Test strategy * @@ -51,10 +53,8 @@ public function testStrategy() \VuFindHarvest\RecordWriterStrategy\IndividualRecordWriterStrategy::class )->onlyMethods(['saveDeletedRecords', 'saveFile']) ->setConstructorArgs(['foo'])->getMock(); - $mock->expects($this->exactly(2))->method('saveDeletedRecords') - ->withConsecutive(['d1'], ['d2']); - $mock->expects($this->exactly(2))->method('saveFile') - ->withConsecutive(['r1'], ['r2']); + $this->expectConsecutiveCalls($mock, 'saveDeletedRecords', [['d1'], ['d2']]); + $this->expectConsecutiveCalls($mock, 'saveFile', [['r1'], ['r2']]); $mock->beginWrite(); $mock->addDeletedRecord('d1'); $mock->addRecord('r1', ''); diff --git a/tests/vufind.php-cs-fixer.php b/tests/vufind.php-cs-fixer.php index d5cdf0b..8b205b7 100644 --- a/tests/vufind.php-cs-fixer.php +++ b/tests/vufind.php-cs-fixer.php @@ -6,8 +6,8 @@ ->in(__DIR__ . '/../src'); $rules = [ - '@PHP80Migration' => true, - '@PHPUnit84Migration:risky' => true, + '@PHP81Migration' => true, + '@PHPUnit100Migration:risky' => true, '@PSR12' => true, 'align_multiline_comment' => true, 'binary_operator_spaces' => [ @@ -45,8 +45,8 @@ 'no_php4_constructor' => true, 'no_singleline_whitespace_before_semicolons' => true, 'no_spaces_around_offset' => true, + 'no_unneeded_braces' => true, 'no_unneeded_control_parentheses' => true, - 'no_unneeded_curly_braces' => true, 'no_unneeded_final_method' => true, 'no_unreachable_default_argument_value' => true, 'no_unused_imports' => true,