diff --git a/.travis.yml b/.travis.yml index a764af4..77c5ea3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,17 +28,24 @@ matrix: - php: 7.3 fast_finish: true include: - - php: 5.5 - env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" COVERAGE=true TEST_COMMAND="composer test-ci" PULI_VERSION=1.0.0-beta9 - + - name: PHPSpec code coverage + php: 5.5 + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" COVERAGE=true TEST_COMMAND="composer test-ci" PULI_VERSION=1.0.0-beta9 DEPENDENCIES="henrikbjorn/phpspec-code-coverage:^2.0.2" + - name: PHPUnit tests + php: 7.2 + env: TEST_COMMAND="./vendor/bin/phpunit" DEPENDENCIES="phpunit/phpunit:^7.5 nyholm/psr7:^1.0 kriswallsmith/buzz:^1.0@beta php-http/curl-client:^1.0 php-http/message" + - name: PHPUnit test with nothing installed + php: 7.2 + env: TEST_COMMAND="./vendor/bin/phpunit --group=NothingInstalled" DEPENDENCIES="phpunit/phpunit:^7.5" before_install: - if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi + - if ! [ -z "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi; install: - wget https://github.com/puli/cli/releases/download/1.0.0-beta10/puli.phar && chmod +x puli.phar - composer require puli/composer-plugin:${PULI_VERSION} --no-update - - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction + - composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction script: - $TEST_COMMAND diff --git a/composer.json b/composer.json index df1e31a..e6b6414 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,7 @@ "php-http/httplug": "^1.0 || ^2.0", "php-http/message-factory": "^1.0", "puli/composer-plugin": "1.0.0-beta10", - "phpspec/phpspec": "^2.4", - "henrikbjorn/phpspec-code-coverage" : "^2.0.2" + "phpspec/phpspec": "^2.4" }, "suggest": { "puli/composer-plugin": "Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details.", diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..72a6c47 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + + + ./tests + + + + + + NothingInstalled + + + diff --git a/src/Exception/NoCandidateFoundException.php b/src/Exception/NoCandidateFoundException.php index 240b568..e53fb79 100644 --- a/src/Exception/NoCandidateFoundException.php +++ b/src/Exception/NoCandidateFoundException.php @@ -27,9 +27,22 @@ function ($a) { $message = sprintf( 'No valid candidate found using strategy "%s". We tested the following candidates: %s.', $strategy, - implode(', ', $classes) + implode(', ', array_map([$this, 'stringify'], $classes)) ); parent::__construct($message); } + + private function stringify($mixed) + { + if (is_string($mixed)) { + return $mixed; + } + + if (is_array($mixed) && 2 === count($mixed)) { + return sprintf('%s::%s', $this->stringify($mixed[0]), $mixed[1]); + } + + return is_object($mixed) ? get_class($mixed) : gettype($mixed); + } } diff --git a/src/Psr17FactoryDiscovery.php b/src/Psr17FactoryDiscovery.php index 1aa833a..7c70fb4 100644 --- a/src/Psr17FactoryDiscovery.php +++ b/src/Psr17FactoryDiscovery.php @@ -20,7 +20,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery private static function createException($type, Exception $e) { return new \Http\Discovery\Exception\NotFoundException( - 'No psr-17 '.$type.' found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation', + 'No PSR-17 '.$type.' found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation', 0, $e ); diff --git a/src/Strategy/CommonClassesStrategy.php b/src/Strategy/CommonClassesStrategy.php index c2b7e09..ab7e4c0 100644 --- a/src/Strategy/CommonClassesStrategy.php +++ b/src/Strategy/CommonClassesStrategy.php @@ -81,7 +81,12 @@ final class CommonClassesStrategy implements DiscoveryStrategy 'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class], ], ], - Psr18Client::class => [], + Psr18Client::class => [ + [ + 'class' => [self::class, 'buzzInstantiate'], + 'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class], + ], + ], ]; /** diff --git a/tests/Exception/InitializeExceptionTest.php b/tests/Exception/InitializeExceptionTest.php new file mode 100644 index 0000000..a9cdc56 --- /dev/null +++ b/tests/Exception/InitializeExceptionTest.php @@ -0,0 +1,23 @@ +assertInstanceOf(\Http\Discovery\Exception::class, $exception); + } + } +} diff --git a/tests/Exception/NoCandidateFoundExceptionTest.php b/tests/Exception/NoCandidateFoundExceptionTest.php new file mode 100644 index 0000000..a6c2a6b --- /dev/null +++ b/tests/Exception/NoCandidateFoundExceptionTest.php @@ -0,0 +1,67 @@ + 'Foo', 'condition' => true], + ['class' => 'Bar', 'condition' => false], + ]; + $exception = new DiscoveryException\NoCandidateFoundException('Foobar', $candidates); + $this->assertInstanceOf(\Http\Discovery\Exception::class, $exception); + $this->assertStringStartsWith('No valid candidate found using strategy "Foobar".', $exception->getMessage()); + } + + public function testInitializeWithArrayCallable() + { + $candidates = [ + ['class' => ['AnyClass', 'anyFunction'], 'condition' => true], + ]; + + $exception = new DiscoveryException\NoCandidateFoundException('Foobar', $candidates); + $this->assertInstanceOf(\Http\Discovery\Exception::class, $exception); + } + + public function testInitializeWithObjectCallable() + { + $obj = new \stdClass(); + $candidates = [ + ['class' => [$obj, 'anyFunction'], 'condition' => true], + ]; + + $exception = new DiscoveryException\NoCandidateFoundException('Foobar', $candidates); + $this->assertInstanceOf(\Http\Discovery\Exception::class, $exception); + } + + public function testInitializeWithClosure() + { + $obj = \Closure::fromCallable(function () { + $x = 2; + }); + $candidates = [ + ['class' => $obj, 'condition' => true], + ]; + + $exception = new DiscoveryException\NoCandidateFoundException('Foobar', $candidates); + $this->assertInstanceOf(\Http\Discovery\Exception::class, $exception); + } + + public function testInitializeWithAnonymousFunction() + { + $func = function () { + $x = 2; + }; + $candidates = [ + ['class' => $func, 'condition' => true], + ]; + + $exception = new DiscoveryException\NoCandidateFoundException('Foobar', $candidates); + $this->assertInstanceOf(\Http\Discovery\Exception::class, $exception); + } +} diff --git a/tests/Psr17FactoryDiscoveryTest.php b/tests/Psr17FactoryDiscoveryTest.php new file mode 100644 index 0000000..a9d8797 --- /dev/null +++ b/tests/Psr17FactoryDiscoveryTest.php @@ -0,0 +1,47 @@ +assertInstanceOf($interface, $client); + } + + /** + * @group NothingInstalled + * @dataProvider getFactories + */ + public function testNotFound($method) + { + $callable = [Psr17FactoryDiscovery::class, $method]; + $this->expectException(NotFoundException::class); + $callable(); + } + + public function getFactories() + { + yield ['findRequestFactory', RequestFactoryInterface::class]; + yield ['findResponseFactory', ResponseFactoryInterface::class]; + yield ['findServerRequestFactory', ServerRequestFactoryInterface::class]; + yield ['findStreamFactory', StreamFactoryInterface::class]; + yield ['findUploadedFileFactory', UploadedFileFactoryInterface::class]; + yield ['findUrlFactory', UriFactoryInterface::class]; + } +} diff --git a/tests/Psr18ClientDiscoveryTest.php b/tests/Psr18ClientDiscoveryTest.php new file mode 100644 index 0000000..30657b8 --- /dev/null +++ b/tests/Psr18ClientDiscoveryTest.php @@ -0,0 +1,26 @@ +assertInstanceOf(ClientInterface::class, $client); + } + + /** + * @group NothingInstalled + */ + public function testNotFound() + { + $this->expectException(NotFoundException::class); + $client = Psr18ClientDiscovery::find(); + } +}