From a8db4986f85932c201872bbc887030026d70cd7b Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Mon, 10 May 2021 17:46:44 +0200 Subject: [PATCH 01/38] First sweep --- composer.json | 6 +-- phpcs.xml.dist | 7 +++ src/Expectation.php | 21 +++----- src/Matcher/AbstractMatcher.php | 10 ++-- src/Matcher/ClosureMatcher.php | 4 +- src/Matcher/MatcherInterface.php | 8 +-- src/Matcher/RegexMatcher.php | 8 +-- src/Matcher/StringMatcher.php | 8 +-- src/MockBuilder.php | 18 +++---- src/PHPUnit/HttpMockFacade.php | 6 +-- src/PHPUnit/HttpMockFacadeMap.php | 10 ++-- src/PHPUnit/HttpMockTrait.php | 14 ++--- src/PHPUnit/ServerManager.php | 9 ++-- src/Request/UnifiedRequest.php | 80 ++++++++++------------------ src/RequestCollectionFacade.php | 24 +++------ src/RequestStorage.php | 8 +-- src/Response/CallbackResponse.php | 6 +-- src/ResponseBuilder.php | 6 +-- src/Server.php | 10 ++-- tests/Request/UnifiedRequestTest.php | 45 +++++++++------- 20 files changed, 136 insertions(+), 172 deletions(-) create mode 100644 phpcs.xml.dist diff --git a/composer.json b/composer.json index 6a612fc..b330deb 100644 --- a/composer.json +++ b/composer.json @@ -13,15 +13,15 @@ } ], "require": { - "php": "~7.1", + "php": "~7.4", "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", "jeremeamia/superclosure": "~2", - "lstrojny/hmmmath": ">=0.5.0" + "lstrojny/hmmmath": ">=0.5.0", + "slevomat/coding-standard": "^7.0" }, "require-dev": { - "internations/kodierungsregelwerksammlung": "~0.23.0", "internations/testing-component": "1.0.1", "phpunit/phpunit": "^7" }, diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..0dc7fbf --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Expectation.php b/src/Expectation.php index 1429b22..d49c92d 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -10,22 +10,17 @@ class Expectation { /** @var MatcherInterface[] */ - private $matcher = []; + private array $matcher = []; - /** @var MatcherFactory */ - private $matcherFactory; + private MatcherFactory $matcherFactory; - /** @var ResponseBuilder */ - private $responseBuilder; + private ResponseBuilder $responseBuilder; - /** @var Closure */ - private $limiter; + private Closure $limiter; - /** @var ExtractorFactory */ - private $extractorFactory; + private ExtractorFactory $extractorFactory; - /** @var int */ - private $priority; + private int $priority; public function __construct( MockBuilder $mockBuilder, @@ -126,7 +121,7 @@ public function callback(Closure $callback) } /** @return SerializableClosure[] */ - public function getMatcherClosures() + public function getMatcherClosures(): array { $closures = []; @@ -157,7 +152,7 @@ public function getLimiter() return new SerializableClosure($this->limiter); } - private function appendMatcher($matcher, Closure $extractor = null) + private function appendMatcher($matcher, Closure $extractor = null): void { $matcher = $this->createMatcher($matcher); diff --git a/src/Matcher/AbstractMatcher.php b/src/Matcher/AbstractMatcher.php index 429d60b..4a40b53 100644 --- a/src/Matcher/AbstractMatcher.php +++ b/src/Matcher/AbstractMatcher.php @@ -7,14 +7,14 @@ abstract class AbstractMatcher implements MatcherInterface { - protected $extractor; + protected ?Closure $extractor = null; - public function setExtractor(Closure $extractor) + public function setExtractor(Closure $extractor): void { $this->extractor = $extractor; } - protected function createExtractor() + protected function createExtractor(): Closure { if (!$this->extractor) { return static function (Request $request) { @@ -25,9 +25,9 @@ protected function createExtractor() return $this->extractor; } - abstract protected function createMatcher(); + abstract protected function createMatcher(): Closure; - public function getMatcher() + public function getMatcher(): SerializableClosure { $matcher = new SerializableClosure($this->createMatcher()); $extractor = new SerializableClosure($this->createExtractor()); diff --git a/src/Matcher/ClosureMatcher.php b/src/Matcher/ClosureMatcher.php index c528e67..cfe0e22 100644 --- a/src/Matcher/ClosureMatcher.php +++ b/src/Matcher/ClosureMatcher.php @@ -5,14 +5,14 @@ class ClosureMatcher extends AbstractMatcher { - private $closure; + private Closure $closure; public function __construct(Closure $closure) { $this->closure = $closure; } - protected function createMatcher() + protected function createMatcher(): Closure { return $this->closure; } diff --git a/src/Matcher/MatcherInterface.php b/src/Matcher/MatcherInterface.php index a218ceb..aad3383 100644 --- a/src/Matcher/MatcherInterface.php +++ b/src/Matcher/MatcherInterface.php @@ -6,10 +6,6 @@ interface MatcherInterface { - /** - * @return SerializableClosure - */ - public function getMatcher(); - - public function setExtractor(Closure $extractor); + public function getMatcher(): SerializableClosure; + public function setExtractor(Closure $extractor): void; } diff --git a/src/Matcher/RegexMatcher.php b/src/Matcher/RegexMatcher.php index def6154..2a6a594 100644 --- a/src/Matcher/RegexMatcher.php +++ b/src/Matcher/RegexMatcher.php @@ -1,16 +1,18 @@ regex = $regex; } - protected function createMatcher() + protected function createMatcher(): Closure { $regex = $this->regex; diff --git a/src/Matcher/StringMatcher.php b/src/Matcher/StringMatcher.php index 43a112a..05c1e64 100644 --- a/src/Matcher/StringMatcher.php +++ b/src/Matcher/StringMatcher.php @@ -1,16 +1,18 @@ string = $string; } - protected function createMatcher() + protected function createMatcher(): Closure { $string = $this->string; diff --git a/src/MockBuilder.php b/src/MockBuilder.php index c51bc70..ffd0d20 100644 --- a/src/MockBuilder.php +++ b/src/MockBuilder.php @@ -12,19 +12,15 @@ class MockBuilder private const PRIORITY_NTH = 100; /** @var Expectation[] */ - private $expectations = []; + private array $expectations = []; - /** @var MatcherFactory */ - private $matcherFactory; + private MatcherFactory $matcherFactory; - /** @var Closure */ - private $limiter; + private Closure $limiter; - /** @var ExtractorFactory */ - private $extractorFactory; + private ExtractorFactory $extractorFactory; - /** @var int */ - private $priority; + private int $priority; public function __construct(MatcherFactory $matcherFactory, ExtractorFactory $extractorFactory) { @@ -93,8 +89,8 @@ public function any() return $this; } - /** @return Expectation */ - public function when() + /***/ + public function when(): Expectation { $this->expectations[] = new Expectation( $this, diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index 9b0dbbf..dbd83cf 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -19,7 +19,7 @@ class HttpMockFacade { /** @var array */ - private $services = []; + private array $services = []; private $basePath; @@ -36,7 +36,7 @@ public static function getProperties() return ['server', 'matches', 'mock', 'requests', 'client']; } - public function setUp() + public function setUp(): void { $this->server->setUp($this->mock->flushExpectations()); } @@ -80,7 +80,7 @@ public function __clone() $this->server->clean(); } - public function each(callable $callback) + public function each(callable $callback): void { $callback($this); } diff --git a/src/PHPUnit/HttpMockFacadeMap.php b/src/PHPUnit/HttpMockFacadeMap.php index 90aadab..07db20b 100644 --- a/src/PHPUnit/HttpMockFacadeMap.php +++ b/src/PHPUnit/HttpMockFacadeMap.php @@ -9,7 +9,7 @@ class HttpMockFacadeMap implements ArrayAccess { /** @var HttpMockFacade[] */ - private $facadeMap; + private array $facadeMap; public function __construct(array $facadeMap) { @@ -30,12 +30,12 @@ public function offsetExists($offset) return isset($this->facadeMap[$offset]); } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { throw new BadMethodCallException(__METHOD__); } - public function offsetUnset($offset) + public function offsetUnset($offset): void { throw new BadMethodCallException(__METHOD__); } @@ -50,12 +50,12 @@ static function (HttpMockFacade $facade) { ); } - public function each(callable $callback) + public function each(callable $callback): void { array_map($callback, $this->facadeMap); } - public function __get($property) + public function __get($property): void { if (in_array($property, HttpMockFacade::getProperties(), true)) { throw new OutOfBoundsException( diff --git a/src/PHPUnit/HttpMockTrait.php b/src/PHPUnit/HttpMockTrait.php index 51afa3d..14d1f36 100644 --- a/src/PHPUnit/HttpMockTrait.php +++ b/src/PHPUnit/HttpMockTrait.php @@ -19,7 +19,7 @@ public static function getHttpMockDefaultHost() /** @var HttpMockFacade|HttpMockFacadeMap */ protected $http; - protected static function setUpHttpMockBeforeClass($port = null, $host = null, $basePath = null, $name = null) + protected static function setUpHttpMockBeforeClass($port = null, $host = null, $basePath = null, $name = null): void { $port = $port ?: static::getHttpMockDefaultPort(); $host = $host ?: static::getHttpMockDefaultHost(); @@ -37,14 +37,14 @@ protected static function setUpHttpMockBeforeClass($port = null, $host = null, $ ServerManager::getInstance()->add($facade->server); } - protected function setUpHttpMock() + protected function setUpHttpMock(): void { static::assertHttpMockSetup(); $this->http = clone static::$staticHttp; } - protected static function assertHttpMockSetup() + protected static function assertHttpMockSetup(): void { if (!static::$staticHttp) { static::fail( @@ -57,7 +57,7 @@ protected static function assertHttpMockSetup() } } - protected function tearDownHttpMock() + protected function tearDownHttpMock(): void { if (!$this->http) { return; @@ -66,7 +66,7 @@ protected function tearDownHttpMock() $http = $this->http; $this->http = null; $http->each( - function (HttpMockFacade $facade) { + function (HttpMockFacade $facade): void { $this->assertSame( '', (string) $facade->server->getIncrementalErrorOutput(), @@ -76,10 +76,10 @@ function (HttpMockFacade $facade) { ); } - protected static function tearDownHttpMockAfterClass() + protected static function tearDownHttpMockAfterClass(): void { static::$staticHttp->each( - static function (HttpMockFacade $facade) { + static function (HttpMockFacade $facade): void { $facade->server->stop(); ServerManager::getInstance()->remove($facade->server); } diff --git a/src/PHPUnit/ServerManager.php b/src/PHPUnit/ServerManager.php index 7f24e90..63ba230 100644 --- a/src/PHPUnit/ServerManager.php +++ b/src/PHPUnit/ServerManager.php @@ -14,9 +14,8 @@ final class ServerManager private static $instance; /** - * @return self */ - public static function getInstance() + public static function getInstance(): self { if (!static::$instance) { static::$instance = new static(); @@ -25,17 +24,17 @@ public static function getInstance() return static::$instance; } - public function add(Server $server) + public function add(Server $server): void { $this->servers->attach($server); } - public function remove(Server $server) + public function remove(Server $server): void { $this->servers->detach($server); } - public function cleanup() + public function cleanup(): void { foreach ($this->servers as $server) { $server->stop(); diff --git a/src/Request/UnifiedRequest.php b/src/Request/UnifiedRequest.php index 45dfed3..3777cb7 100644 --- a/src/Request/UnifiedRequest.php +++ b/src/Request/UnifiedRequest.php @@ -13,15 +13,9 @@ class UnifiedRequest { - /** - * @var RequestInterface - */ - private $wrapped; + private RequestInterface $wrapped; - /** - * @var string - */ - private $userAgent; + private ?string $userAgent = null; public function __construct(RequestInterface $wrapped, array $params = []) { @@ -29,12 +23,7 @@ public function __construct(RequestInterface $wrapped, array $params = []) $this->init($params); } - /** - * Get the user agent of the request - * - * @return string - */ - public function getUserAgent() + public function getUserAgent(): ?string { return $this->userAgent; } @@ -42,9 +31,8 @@ public function getUserAgent() /** * Get the body of the request if set * - * @return EntityBodyInterface|null */ - public function getBody() + public function getBody(): ?EntityBodyInterface { return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); } @@ -56,7 +44,7 @@ public function getBody() * * @return mixed|null */ - public function getPostField($field) + public function getPostField(string $field) { return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); } @@ -64,9 +52,8 @@ public function getPostField($field) /** * Get the post fields that will be used in the request * - * @return QueryString */ - public function getPostFields() + public function getPostFields(): QueryString { return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); } @@ -76,7 +63,7 @@ public function getPostFields() * * @return array */ - public function getPostFiles() + public function getPostFiles(): array { return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); } @@ -88,7 +75,7 @@ public function getPostFiles() * * @return array|null Returns an array wrapping an array of PostFileInterface objects */ - public function getPostFile($fieldName) + public function getPostFile(string $fieldName): ?array { return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); } @@ -96,9 +83,8 @@ public function getPostFile($fieldName) /** * Get application and plugin specific parameters set on the message. * - * @return Collection */ - public function getParams() + public function getParams(): Collection { return $this->wrapped->getParams(); } @@ -111,7 +97,7 @@ public function getParams() * @return Header|null Returns NULL if no matching header is found. * Returns a Header object if found. */ - public function getHeader($header) + public function getHeader(string $header): ?Header { return $this->wrapped->getHeader($header); } @@ -119,9 +105,8 @@ public function getHeader($header) /** * Get all headers as a collection * - * @return HeaderCollection */ - public function getHeaders() + public function getHeaders(): HeaderCollection { return $this->wrapped->getHeaders(); } @@ -131,7 +116,7 @@ public function getHeaders() * * @return array */ - public function getHeaderLines() + public function getHeaderLines(): array { return $this->wrapped->getHeaderLines(); } @@ -143,7 +128,7 @@ public function getHeaderLines() * * @return bool Returns TRUE or FALSE if the header is present */ - public function hasHeader($header) + public function hasHeader(string $header): bool { return $this->wrapped->hasHeader($header); } @@ -151,9 +136,8 @@ public function hasHeader($header) /** * Get the raw message headers as a string * - * @return string */ - public function getRawHeaders() + public function getRawHeaders(): string { return $this->wrapped->getRawHeaders(); } @@ -162,9 +146,8 @@ public function getRawHeaders() * Get the collection of key value pairs that will be used as the query * string in the request * - * @return QueryString */ - public function getQuery() + public function getQuery(): QueryString { return $this->wrapped->getQuery(); } @@ -172,9 +155,8 @@ public function getQuery() /** * Get the HTTP method of the request * - * @return string */ - public function getMethod() + public function getMethod(): string { return $this->wrapped->getMethod(); } @@ -182,9 +164,8 @@ public function getMethod() /** * Get the URI scheme of the request (http, https, ftp, etc) * - * @return string */ - public function getScheme() + public function getScheme(): string { return $this->wrapped->getScheme(); } @@ -192,9 +173,8 @@ public function getScheme() /** * Get the host of the request * - * @return string */ - public function getHost() + public function getHost(): string { return $this->wrapped->getHost(); } @@ -202,9 +182,8 @@ public function getHost() /** * Get the HTTP protocol version of the request * - * @return string */ - public function getProtocolVersion() + public function getProtocolVersion(): string { return $this->wrapped->getProtocolVersion(); } @@ -212,9 +191,8 @@ public function getProtocolVersion() /** * Get the path of the request (e.g. '/', '/index.html') * - * @return string */ - public function getPath() + public function getPath(): string { return $this->wrapped->getPath(); } @@ -222,9 +200,8 @@ public function getPath() /** * Get the port that the request will be sent on if it has been set * - * @return int|null */ - public function getPort() + public function getPort(): ?int { return $this->wrapped->getPort(); } @@ -232,9 +209,8 @@ public function getPort() /** * Get the username to pass in the URL if set * - * @return string|null */ - public function getUsername() + public function getUsername(): ?string { return $this->wrapped->getUsername(); } @@ -242,9 +218,8 @@ public function getUsername() /** * Get the password to pass in the URL if set * - * @return string|null */ - public function getPassword() + public function getPassword(): ?string { return $this->wrapped->getPassword(); } @@ -257,7 +232,7 @@ public function getPassword() * * @return string|Url */ - public function getUrl($asObject = false) + public function getUrl(bool $asObject = false) { return $this->wrapped->getUrl($asObject); } @@ -267,7 +242,7 @@ public function getUrl($asObject = false) * * @return array */ - public function getCookies() + public function getCookies(): array { return $this->wrapped->getCookies(); } @@ -277,9 +252,8 @@ public function getCookies() * * @param string $name Cookie to retrieve * - * @return null|string */ - public function getCookie($name) + public function getCookie(string $name): ?string { return $this->wrapped->getCookie($name); } @@ -301,7 +275,7 @@ protected function invokeWrappedIfEntityEnclosed($method, array $params = []) return call_user_func_array([$this->wrapped, $method], $params); } - private function init(array $params) + private function init(array $params): void { foreach ($params as $property => $value) { if (property_exists($this, $property)) { diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index 850723e..93ea03f 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -20,50 +20,43 @@ public function __construct(ClientInterface $client) } /** - * @return UnifiedRequest */ - public function latest() + public function latest(): UnifiedRequest { return $this->getRecordedRequest('/_request/last'); } /** - * @return UnifiedRequest */ - public function last() + public function last(): UnifiedRequest { return $this->getRecordedRequest('/_request/last'); } /** - * @return UnifiedRequest */ - public function first() + public function first(): UnifiedRequest { return $this->getRecordedRequest('/_request/first'); } /** - * @param int $position - * @return UnifiedRequest */ - public function at($position) + public function at(int $position): UnifiedRequest { return $this->getRecordedRequest('/_request/' . $position); } /** - * @return UnifiedRequest */ - public function pop() + public function pop(): UnifiedRequest { return $this->deleteRecordedRequest('/_request/last'); } /** - * @return UnifiedRequest */ - public function shift() + public function shift(): UnifiedRequest { return $this->deleteRecordedRequest('/_request/first'); } @@ -78,12 +71,9 @@ public function count() } /** - * @param Response $response - * @param string $path * @throws UnexpectedValueException - * @return UnifiedRequest */ - private function parseRequestFromResponse(Response $response, $path) + private function parseRequestFromResponse(Response $response, string $path): UnifiedRequest { try { $requestInfo = Util::deserialize($response->getBody()); diff --git a/src/RequestStorage.php b/src/RequestStorage.php index f2838f8..abe4ce0 100644 --- a/src/RequestStorage.php +++ b/src/RequestStorage.php @@ -15,7 +15,7 @@ public function __construct($pid, $directory) $this->directory = $directory; } - public function store(Request $request, $name, $data) + public function store(Request $request, $name, $data): void { file_put_contents($this->getFileName($request, $name), serialize($data)); } @@ -31,14 +31,14 @@ public function read(Request $request, $name) return Util::deserialize(file_get_contents($fileName)); } - public function append(Request $request, $name, $data) + public function append(Request $request, $name, $data): void { $list = $this->read($request, $name); $list[] = $data; $this->store($request, $name, $list); } - public function prepend(Request $request, $name, $data) + public function prepend(Request $request, $name, $data): void { $list = $this->read($request, $name); array_unshift($list, $data); @@ -50,7 +50,7 @@ private function getFileName(Request $request, $name) return $this->directory . $this->pid . '-' . $name . '-' . $request->server->get('SERVER_PORT'); } - public function clear(Request $request, $name) + public function clear(Request $request, $name): void { $fileName = $this->getFileName($request, $name); diff --git a/src/Response/CallbackResponse.php b/src/Response/CallbackResponse.php index 025979c..e9aeb58 100644 --- a/src/Response/CallbackResponse.php +++ b/src/Response/CallbackResponse.php @@ -7,12 +7,12 @@ class CallbackResponse extends Response { private $callback; - public function setCallback(callable $callback) + public function setCallback(callable $callback): void { $this->callback = $callback; } - public function sendCallback() + public function sendCallback(): void { if ($this->callback) { $callback = $this->callback; @@ -20,7 +20,7 @@ public function sendCallback() } } - public function send() + public function send(): void { $this->sendCallback(); parent::send(); diff --git a/src/ResponseBuilder.php b/src/ResponseBuilder.php index 62890ba..7434a31 100644 --- a/src/ResponseBuilder.php +++ b/src/ResponseBuilder.php @@ -7,11 +7,9 @@ class ResponseBuilder { - /** @var MockBuilder */ - private $mockBuilder; + private MockBuilder $mockBuilder; - /** @var CallbackResponse */ - private $response; + private CallbackResponse $response; public function __construct(MockBuilder $mockBuilder) { diff --git a/src/Server.php b/src/Server.php index b1b7a8c..ef10872 100644 --- a/src/Server.php +++ b/src/Server.php @@ -34,7 +34,7 @@ public function __construct($port, $host) $this->setTimeout(null); } - public function start(callable $callback = null, array $env = []) + public function start(callable $callback = null, array $env = []): void { parent::start($callback, $env); @@ -56,7 +56,7 @@ private function createClient() $client = new Client($this->getBaseUrl()); $client->getEventDispatcher()->addListener( 'request.error', - static function (Event $event) { + static function (Event $event): void { $event->stopPropagation(); } ); @@ -78,7 +78,7 @@ public function getConnectionString() * @param Expectation[] $expectations * @throws RuntimeException */ - public function setUp(array $expectations) + public function setUp(array $expectations): void { /** @var Expectation $expectation */ foreach ($expectations as $expectation) { @@ -98,7 +98,7 @@ public function setUp(array $expectations) } } - public function clean() + public function clean(): void { if (!$this->isRunning()) { $this->start(); @@ -107,7 +107,7 @@ public function clean() $this->getClient()->delete('/_all')->send(); } - private function pollWait() + private function pollWait(): void { foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) { try { diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php index 479a384..0d3be75 100644 --- a/tests/Request/UnifiedRequestTest.php +++ b/tests/Request/UnifiedRequestTest.php @@ -1,7 +1,12 @@ 'Bar']], ['getRawHeaders'], - ['getQuery'], + ['getQuery', [], new QueryString()], ['getMethod'], ['getScheme'], ['getHost'], ['getProtocolVersion'], ['getPath'], - ['getPort'], + ['getPort', [], 8080], ['getUsername'], ['getPassword'], ['getUrl'], - ['getCookies'], - ['getHeader', ['header']], - ['hasHeader', ['header']], + ['getCookies', [], []], + ['getHeader', ['header'], new Header('Foo', 'Bar')], + ['hasHeader', ['header'], true], ['getUrl', [false]], ['getUrl', [true]], ['getCookie', ['cookieName']], @@ -58,47 +63,47 @@ public static function provideMethods() public static function provideEntityEnclosingInterfaceMethods() { return [ - ['getBody'], + ['getBody', [], EntityBody::fromString('foo')], ['getPostField', ['postField']], - ['getPostFields'], - ['getPostFiles'], - ['getPostFile', ['fileName']], + ['getPostFields', [], new QueryString()], + ['getPostFiles', [], []], + ['getPostFile', ['fileName'], []], ]; } /** @dataProvider provideMethods */ - public function testMethodsFromRequestInterface($method, array $params = []) + public function testMethodsFromRequestInterface($method, array $params = [], $returnValue = 'REQ') { $this->wrappedRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue('REQ')) + ->will($this->returnValue($returnValue)) ->with(...$params); - $this->assertSame('REQ', call_user_func_array([$this->unifiedRequest, $method], $params)); + $this->assertSame($returnValue, call_user_func_array([$this->unifiedRequest, $method], $params)); $this->wrappedEntityEnclosingRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue('ENTITY_ENCL_REQ')) + ->will($this->returnValue($returnValue)) ->with(...$params); $this->assertSame( - 'ENTITY_ENCL_REQ', + $returnValue, call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) ); } /** @dataProvider provideEntityEnclosingInterfaceMethods */ - public function testEntityEnclosingInterfaceMethods($method, array $params = []) + public function testEntityEnclosingInterfaceMethods($method, array $params = [], $returnValue = 'Return Value') { $this->wrappedEntityEnclosingRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue('ENTITY_ENCL_REQ')) + ->will($this->returnValue($returnValue)) ->with(...$params); $this->assertSame( - 'ENTITY_ENCL_REQ', + $returnValue, call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) ); From 1e31b63dddf807af35f804a6a9dc193afa83aec5 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Mon, 10 May 2021 17:52:47 +0200 Subject: [PATCH 02/38] Next --- src/Expectation.php | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/Expectation.php b/src/Expectation.php index d49c92d..5acbdad 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -6,14 +6,13 @@ use InterNations\Component\HttpMock\Matcher\MatcherInterface; use SuperClosure\SerializableClosure; use Closure; +use Symfony\Component\HttpFoundation\Response; class Expectation { /** @var MatcherInterface[] */ private array $matcher = []; - private MatcherFactory $matcherFactory; - private ResponseBuilder $responseBuilder; private Closure $limiter; @@ -37,42 +36,46 @@ public function __construct( $this->priority = $priority; } - public function pathIs($matcher) + /** @param string|MatcherInterface $matcher */ + public function pathIs($matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createPathExtractor()); return $this; } - public function methodIs($matcher) + /** @param string|MatcherInterface $matcher */ + public function methodIs($matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createMethodExtractor()); return $this; } - public function queryParamIs($param, $matcher) + /** @param string|MatcherInterface $matcher */ + public function queryParamIs(string $param, $matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createParamExtractor($param)); return $this; } - public function queryParamExists($param) + public function queryParamExists(string $param): self { $this->appendMatcher(true, $this->extractorFactory->createParamExistsExtractor($param)); return $this; } - public function queryParamNotExists($param) + public function queryParamNotExists(string $param): self { $this->appendMatcher(false, $this->extractorFactory->createParamExistsExtractor($param)); return $this; } - public function queryParamsAre(array $paramMap) + /** @param array $paramMap */ + public function queryParamsAre(array $paramMap): self { foreach ($paramMap as $param => $value) { $this->queryParamIs($param, $value); @@ -81,7 +84,8 @@ public function queryParamsAre(array $paramMap) return $this; } - public function queryParamsExist(array $params) + /** @param string[] $params */ + public function queryParamsExist(array $params): self { foreach ($params as $param) { $this->queryParamExists($param); @@ -90,7 +94,8 @@ public function queryParamsExist(array $params) return $this; } - public function queryParamsNotExist(array $params) + /** @param string[] $params */ + public function queryParamsNotExist(array $params): self { foreach ($params as $param) { $this->queryParamNotExists($param); @@ -99,21 +104,22 @@ public function queryParamsNotExist(array $params) return $this; } - public function headerIs($name, $value) + /** @param string|MatcherInterface $value */ + public function headerIs(string $name, $value): self { $this->appendMatcher($value, $this->extractorFactory->createHeaderExtractor($name)); return $this; } - public function headerExists($name) + public function headerExists(string $name): self { $this->appendMatcher(true, $this->extractorFactory->createHeaderExistsExtractor($name)); return $this; } - public function callback(Closure $callback) + public function callback(Closure $callback): self { $this->appendMatcher($this->matcherFactory->closure($callback)); @@ -132,26 +138,27 @@ public function getMatcherClosures(): array return $closures; } - public function getPriority() + public function getPriority(): int { return $this->priority; } - public function then() + public function then(): ResponseBuilder { return $this->responseBuilder; } - public function getResponse() + public function getResponse(): Response { return $this->responseBuilder->getResponse(); } - public function getLimiter() + public function getLimiter(): SerializableClosure { return new SerializableClosure($this->limiter); } + /** @param string|MatcherInterface $matcher */ private function appendMatcher($matcher, Closure $extractor = null): void { $matcher = $this->createMatcher($matcher); @@ -163,7 +170,8 @@ private function appendMatcher($matcher, Closure $extractor = null): void $this->matcher[] = $matcher; } - private function createMatcher($matcher) + /** @param string|MatcherInterface $matcher */ + private function createMatcher($matcher): MatcherInterface { return $matcher instanceof MatcherInterface ? $matcher : $this->matcherFactory->str($matcher); } From 86febbaefff27e60404d6357cfdb744878915173 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Mon, 10 May 2021 21:27:33 +0200 Subject: [PATCH 03/38] Next --- doc/start.md | 19 ++-- phpcs.xml.dist | 50 ++++++++++ src/Expectation.php | 28 +++--- src/Matcher/ClosureMatcher.php | 2 +- ...tMatcher.php => ExtractorBasedMatcher.php} | 2 +- src/Matcher/ExtractorFactory.php | 18 ++-- .../{MatcherInterface.php => Matcher.php} | 2 +- src/Matcher/MatcherFactory.php | 8 +- src/Matcher/RegexMatcher.php | 2 +- src/Matcher/StringMatcher.php | 2 +- src/MockBuilder.php | 25 ++--- src/PHPUnit/HttpMock.php | 95 +++++++++++++++++++ src/PHPUnit/HttpMockFacade.php | 25 ++--- src/PHPUnit/HttpMockFacadeMap.php | 10 +- src/PHPUnit/HttpMockTrait.php | 88 ++--------------- src/PHPUnit/ServerManager.php | 14 +-- src/Request/UnifiedRequest.php | 27 ++++-- src/RequestCollectionFacade.php | 25 +++-- src/RequestStorage.php | 28 +++--- src/Response/CallbackResponse.php | 9 +- src/ResponseBuilder.php | 16 ++-- src/Server.php | 40 ++++---- src/Util.php | 8 +- src/app.php | 10 +- tests/AppIntegrationTest.php | 36 +++---- tests/Fixtures/Request.php | 4 +- tests/Matcher/ExtractorFactoryTest.php | 24 +++-- tests/Matcher/StringMatcherTest.php | 2 +- tests/MockBuilderIntegrationTest.php | 26 +++-- .../HttpMockMultiPHPUnitIntegrationTest.php | 40 ++++---- ...HttpMockPHPUnitIntegrationBasePathTest.php | 14 +-- .../HttpMockPHPUnitIntegrationTest.php | 50 +++++----- tests/Request/UnifiedRequestTest.php | 21 ++-- tests/RequestCollectionFacadeTest.php | 29 +++--- 34 files changed, 441 insertions(+), 358 deletions(-) rename src/Matcher/{AbstractMatcher.php => ExtractorBasedMatcher.php} (94%) rename src/Matcher/{MatcherInterface.php => Matcher.php} (89%) create mode 100644 src/PHPUnit/HttpMock.php diff --git a/doc/start.md b/doc/start.md index b972367..83fa653 100644 --- a/doc/start.md +++ b/doc/start.md @@ -7,33 +7,34 @@ server in `setUpBeforeClass()` and `tearDownAfterClass()` respectively. ```php namespace Acme\Tests; -use InterNations\Component\HttpMock\PHPUnit\HttpMockTrait; +use PHPUnit\Framework\TestCase; +use InterNations\Component\HttpMock\PHPUnit\HttpMock; -class ExampleTest extends PHPUnit_Framework_TestCase +class ExampleTest extends TestCase { - use HttpMockTrait; + use HttpMock; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { static::setUpHttpMockBeforeClass('8082', 'localhost'); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { static::tearDownHttpMockAfterClass(); } - public function setUp() + protected function setUp(): void { $this->setUpHttpMock(); } - public function tearDown() + protected function tearDown(): void { $this->tearDownHttpMock(); } - public function testSimpleRequest() + public function testSimpleRequest(): void { $this->http->mock ->when() @@ -47,7 +48,7 @@ class ExampleTest extends PHPUnit_Framework_TestCase $this->assertSame('mocked body', file_get_contents('http://localhost:8082/foo')); } - public function testAccessingRecordedRequests() + public function testAccessingRecordedRequests(): void { $this->http->mock ->when() diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 0dc7fbf..c10c59a 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -4,4 +4,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Expectation.php b/src/Expectation.php index 5acbdad..c1d3fe5 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -3,14 +3,14 @@ use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\HttpMock\Matcher\MatcherFactory; -use InterNations\Component\HttpMock\Matcher\MatcherInterface; +use InterNations\Component\HttpMock\Matcher\Matcher; use SuperClosure\SerializableClosure; use Closure; use Symfony\Component\HttpFoundation\Response; class Expectation { - /** @var MatcherInterface[] */ + /** @var array */ private array $matcher = []; private MatcherFactory $matcherFactory; private ResponseBuilder $responseBuilder; @@ -36,7 +36,7 @@ public function __construct( $this->priority = $priority; } - /** @param string|MatcherInterface $matcher */ + /** @param string|Matcher $matcher */ public function pathIs($matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createPathExtractor()); @@ -44,7 +44,7 @@ public function pathIs($matcher): self return $this; } - /** @param string|MatcherInterface $matcher */ + /** @param string|Matcher $matcher */ public function methodIs($matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createMethodExtractor()); @@ -52,7 +52,7 @@ public function methodIs($matcher): self return $this; } - /** @param string|MatcherInterface $matcher */ + /** @param string|Matcher $matcher */ public function queryParamIs(string $param, $matcher): self { $this->appendMatcher($matcher, $this->extractorFactory->createParamExtractor($param)); @@ -74,7 +74,7 @@ public function queryParamNotExists(string $param): self return $this; } - /** @param array $paramMap */ + /** @param array $paramMap */ public function queryParamsAre(array $paramMap): self { foreach ($paramMap as $param => $value) { @@ -84,7 +84,7 @@ public function queryParamsAre(array $paramMap): self return $this; } - /** @param string[] $params */ + /** @param array $params */ public function queryParamsExist(array $params): self { foreach ($params as $param) { @@ -94,7 +94,7 @@ public function queryParamsExist(array $params): self return $this; } - /** @param string[] $params */ + /** @param array $params */ public function queryParamsNotExist(array $params): self { foreach ($params as $param) { @@ -104,7 +104,7 @@ public function queryParamsNotExist(array $params): self return $this; } - /** @param string|MatcherInterface $value */ + /** @param string|Matcher $value */ public function headerIs(string $name, $value): self { $this->appendMatcher($value, $this->extractorFactory->createHeaderExtractor($name)); @@ -126,7 +126,7 @@ public function callback(Closure $callback): self return $this; } - /** @return SerializableClosure[] */ + /** @return array */ public function getMatcherClosures(): array { $closures = []; @@ -158,7 +158,7 @@ public function getLimiter(): SerializableClosure return new SerializableClosure($this->limiter); } - /** @param string|MatcherInterface $matcher */ + /** @param string|Matcher $matcher */ private function appendMatcher($matcher, Closure $extractor = null): void { $matcher = $this->createMatcher($matcher); @@ -170,9 +170,9 @@ private function appendMatcher($matcher, Closure $extractor = null): void $this->matcher[] = $matcher; } - /** @param string|MatcherInterface $matcher */ - private function createMatcher($matcher): MatcherInterface + /** @param string|Matcher $matcher */ + private function createMatcher($matcher): Matcher { - return $matcher instanceof MatcherInterface ? $matcher : $this->matcherFactory->str($matcher); + return $matcher instanceof Matcher ? $matcher : $this->matcherFactory->str($matcher); } } diff --git a/src/Matcher/ClosureMatcher.php b/src/Matcher/ClosureMatcher.php index cfe0e22..1362c34 100644 --- a/src/Matcher/ClosureMatcher.php +++ b/src/Matcher/ClosureMatcher.php @@ -3,7 +3,7 @@ use Closure; -class ClosureMatcher extends AbstractMatcher +class ClosureMatcher extends ExtractorBasedMatcher { private Closure $closure; diff --git a/src/Matcher/AbstractMatcher.php b/src/Matcher/ExtractorBasedMatcher.php similarity index 94% rename from src/Matcher/AbstractMatcher.php rename to src/Matcher/ExtractorBasedMatcher.php index 4a40b53..82c0822 100644 --- a/src/Matcher/AbstractMatcher.php +++ b/src/Matcher/ExtractorBasedMatcher.php @@ -5,7 +5,7 @@ use SuperClosure\SerializableClosure; use Symfony\Component\HttpFoundation\Request; -abstract class AbstractMatcher implements MatcherInterface +abstract class ExtractorBasedMatcher implements Matcher { protected ?Closure $extractor = null; diff --git a/src/Matcher/ExtractorFactory.php b/src/Matcher/ExtractorFactory.php index 0faecb9..1f38850 100644 --- a/src/Matcher/ExtractorFactory.php +++ b/src/Matcher/ExtractorFactory.php @@ -3,16 +3,16 @@ use Symfony\Component\HttpFoundation\Request; -class ExtractorFactory +final class ExtractorFactory { - private $basePath; + private string $basePath; - public function __construct($basePath = '') + public function __construct(?string $basePath = null) { $this->basePath = rtrim($basePath, '/'); } - public function createPathExtractor() + public function createPathExtractor(): callable { $basePath = $this->basePath; @@ -21,35 +21,35 @@ public function createPathExtractor() }; } - public function createMethodExtractor() + public function createMethodExtractor(): callable { return static function (Request $request) { return $request->getMethod(); }; } - public function createParamExtractor($param) + public function createParamExtractor(string $param): callable { return static function (Request $request) use ($param) { return $request->query->get($param); }; } - public function createParamExistsExtractor($param) + public function createParamExistsExtractor(string $param): callable { return static function (Request $request) use ($param) { return $request->query->has($param); }; } - public function createHeaderExtractor($header) + public function createHeaderExtractor(string $header): callable { return static function (Request $request) use ($header) { return $request->headers->get($header); }; } - public function createHeaderExistsExtractor($header) + public function createHeaderExistsExtractor(string $header): callable { return static function (Request $request) use ($header) { return $request->headers->has($header); diff --git a/src/Matcher/MatcherInterface.php b/src/Matcher/Matcher.php similarity index 89% rename from src/Matcher/MatcherInterface.php rename to src/Matcher/Matcher.php index aad3383..2c88478 100644 --- a/src/Matcher/MatcherInterface.php +++ b/src/Matcher/Matcher.php @@ -4,7 +4,7 @@ use SuperClosure\SerializableClosure; use Closure; -interface MatcherInterface +interface Matcher { public function getMatcher(): SerializableClosure; public function setExtractor(Closure $extractor): void; diff --git a/src/Matcher/MatcherFactory.php b/src/Matcher/MatcherFactory.php index 34d5461..d32f841 100644 --- a/src/Matcher/MatcherFactory.php +++ b/src/Matcher/MatcherFactory.php @@ -3,19 +3,19 @@ use Closure; -class MatcherFactory +final class MatcherFactory { - public function regex($regex) + public function regex(string $regex): Matcher { return new RegexMatcher($regex); } - public function str($string) + public function str(string $string): Matcher { return new StringMatcher($string); } - public function closure(Closure $closure) + public function closure(Closure $closure): Matcher { return new ClosureMatcher($closure); } diff --git a/src/Matcher/RegexMatcher.php b/src/Matcher/RegexMatcher.php index 2a6a594..5ec7ade 100644 --- a/src/Matcher/RegexMatcher.php +++ b/src/Matcher/RegexMatcher.php @@ -3,7 +3,7 @@ use Closure; -class RegexMatcher extends AbstractMatcher +class RegexMatcher extends ExtractorBasedMatcher { private string $regex; diff --git a/src/Matcher/StringMatcher.php b/src/Matcher/StringMatcher.php index 05c1e64..c863b6d 100644 --- a/src/Matcher/StringMatcher.php +++ b/src/Matcher/StringMatcher.php @@ -3,7 +3,7 @@ use Closure; -class StringMatcher extends AbstractMatcher +class StringMatcher extends ExtractorBasedMatcher { private string $string; diff --git a/src/MockBuilder.php b/src/MockBuilder.php index ffd0d20..32cbc80 100644 --- a/src/MockBuilder.php +++ b/src/MockBuilder.php @@ -11,7 +11,7 @@ class MockBuilder private const PRIORITY_EXACTLY = 10; private const PRIORITY_NTH = 100; - /** @var Expectation[] */ + /** @var array */ private array $expectations = []; private MatcherFactory $matcherFactory; @@ -29,22 +29,22 @@ public function __construct(MatcherFactory $matcherFactory, ExtractorFactory $ex $this->any(); } - public function once() + public function once(): self { return $this->exactly(1); } - public function twice() + public function twice(): self { return $this->exactly(2); } - public function thrice() + public function thrice(): self { return $this->exactly(3); } - public function exactly($times) + public function exactly(int $times): self { $this->limiter = static function ($runs) use ($times) { return $runs < $times; @@ -54,32 +54,32 @@ public function exactly($times) return $this; } - public function first() + public function first(): self { return $this->nth(1); } - public function second() + public function second(): self { return $this->nth(2); } - public function third() + public function third(): self { return $this->nth(3); } - public function nth($position) + public function nth(int $position): self { $this->limiter = static function ($runs) use ($position) { - return $runs === ($position - 1); + return $runs === $position - 1; }; $this->priority = $position * self::PRIORITY_NTH; return $this; } - public function any() + public function any(): self { $this->limiter = static function () { return true; @@ -105,7 +105,8 @@ public function when(): Expectation return end($this->expectations); } - public function flushExpectations() + /** @return list */ + public function flushExpectations(): array { $expectations = $this->expectations; $this->expectations = []; diff --git a/src/PHPUnit/HttpMock.php b/src/PHPUnit/HttpMock.php new file mode 100644 index 0000000..3ed8992 --- /dev/null +++ b/src/PHPUnit/HttpMock.php @@ -0,0 +1,95 @@ + $facade] + static::$staticHttp->all()); + } else { + static::$staticHttp = new HttpMockFacadeMap([$name => $facade]); + } + + ServerManager::getInstance()->add($facade->server); + } + + protected function setUpHttpMock(): void + { + static::assertHttpMockSetup(); + + $this->http = clone static::$staticHttp; + } + + protected static function assertHttpMockSetup(): void + { + if (static::$staticHttp) { + return; + } + + static::fail( + sprintf( + 'Static HTTP mock facade not present. Did you forget to invoke static::setUpHttpMockBeforeClass()' + . ' in %s::setUpBeforeClass()?', + static::class + ) + ); + } + + protected function tearDownHttpMock(): void + { + if (!$this->http) { + return; + } + + $http = $this->http; + $this->http = null; + $http->each( + function (HttpMockFacade $facade): void { + $this->assertSame( + '', + (string) $facade->server->getIncrementalErrorOutput(), + 'HTTP mock server standard error output should be empty' + ); + } + ); + } + + protected static function tearDownHttpMockAfterClass(): void + { + static::$staticHttp->each( + static function (HttpMockFacade $facade): void { + $facade->server->stop(); + ServerManager::getInstance()->remove($facade->server); + } + ); + } +} diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index dbd83cf..46946e6 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -1,7 +1,6 @@ */ private array $services = []; - private $basePath; + private ?string $basePath; - public function __construct($port, $host, $basePath) + public function __construct(int $port, string $host, ?string $basePath = null) { $server = new Server($port, $host); $server->start(); @@ -31,7 +30,8 @@ public function __construct($port, $host, $basePath) $this->basePath = $basePath; } - public static function getProperties() + /** @return list */ + public static function getProperties(): array { return ['server', 'matches', 'mock', 'requests', 'client']; } @@ -41,37 +41,28 @@ public function setUp(): void $this->server->setUp($this->mock->flushExpectations()); } - public function __get($property) + public function __get(string $property): object { - if (isset($this->services[$property])) { - return $this->services[$property]; - } - - return $this->services[$property] = $this->createService($property); + return $this->services[$property] ?? ($this->services[$property] = $this->createService($property)); } - private function createService($property) + private function createService(string $property): object { switch ($property) { case 'matches': return new MatcherFactory(); - break; case 'mock': return new MockBuilder($this->matches, new ExtractorFactory($this->basePath)); - break; case 'client': return $this->server->getClient(); - break; case 'requests': return new RequestCollectionFacade($this->client); - break; default: throw new RuntimeException(sprintf('Invalid property "%s" read', $property)); - break; } } diff --git a/src/PHPUnit/HttpMockFacadeMap.php b/src/PHPUnit/HttpMockFacadeMap.php index 07db20b..c6e9c01 100644 --- a/src/PHPUnit/HttpMockFacadeMap.php +++ b/src/PHPUnit/HttpMockFacadeMap.php @@ -8,9 +8,10 @@ /** @property-read HttpMockFacade */ class HttpMockFacadeMap implements ArrayAccess { - /** @var HttpMockFacade[] */ + /** @var array */ private array $facadeMap; + /** @param array $facadeMap */ public function __construct(array $facadeMap) { $this->facadeMap = $facadeMap; @@ -25,7 +26,7 @@ public function offsetGet($offset) return $this->facadeMap[$offset]; } - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->facadeMap[$offset]); } @@ -55,7 +56,7 @@ public function each(callable $callback): void array_map($callback, $this->facadeMap); } - public function __get($property): void + public function __get(string $property): void { if (in_array($property, HttpMockFacade::getProperties(), true)) { throw new OutOfBoundsException( @@ -77,7 +78,8 @@ public function __get($property): void ); } - public function all() + /** @return array */ + public function all(): array { return $this->facadeMap; } diff --git a/src/PHPUnit/HttpMockTrait.php b/src/PHPUnit/HttpMockTrait.php index 14d1f36..cd01edd 100644 --- a/src/PHPUnit/HttpMockTrait.php +++ b/src/PHPUnit/HttpMockTrait.php @@ -1,88 +1,12 @@ $facade] + static::$staticHttp->all()); - } else { - static::$staticHttp = new HttpMockFacadeMap([$name => $facade]); - } +use function trigger_error; +use const E_USER_DEPRECATED; - ServerManager::getInstance()->add($facade->server); - } +trigger_error(E_USER_DEPRECATED, sprintf('%s is deprecated. Use %s instead', HttpMockTrait::class, HttpMock::class)); - protected function setUpHttpMock(): void - { - static::assertHttpMockSetup(); - - $this->http = clone static::$staticHttp; - } - - protected static function assertHttpMockSetup(): void - { - if (!static::$staticHttp) { - static::fail( - sprintf( - 'Static HTTP mock facade not present. Did you forget to invoke static::setUpHttpMockBeforeClass()' - . ' in %s::setUpBeforeClass()?', - get_called_class() - ) - ); - } - } - - protected function tearDownHttpMock(): void - { - if (!$this->http) { - return; - } - - $http = $this->http; - $this->http = null; - $http->each( - function (HttpMockFacade $facade): void { - $this->assertSame( - '', - (string) $facade->server->getIncrementalErrorOutput(), - 'HTTP mock server standard error output should be empty' - ); - } - ); - } - - protected static function tearDownHttpMockAfterClass(): void - { - static::$staticHttp->each( - static function (HttpMockFacade $facade): void { - $facade->server->stop(); - ServerManager::getInstance()->remove($facade->server); - } - ); - } +trait HttpMockTrait +{ + use HttpMock; } diff --git a/src/PHPUnit/ServerManager.php b/src/PHPUnit/ServerManager.php index 63ba230..a6005a3 100644 --- a/src/PHPUnit/ServerManager.php +++ b/src/PHPUnit/ServerManager.php @@ -8,20 +8,14 @@ final class ServerManager // @codingStandardsIgnoreEnd { - /** @var SplObjectStorage|Server[] */ - private $servers; + /** @var SplObjectStorage|iterable */ + private SplObjectStorage $servers; - private static $instance; + private static ?self $instance = null; - /** - */ public static function getInstance(): self { - if (!static::$instance) { - static::$instance = new static(); - } - - return static::$instance; + return self::$instance ?: (self::$instance = new self()); } public function add(Server $server): void diff --git a/src/Request/UnifiedRequest.php b/src/Request/UnifiedRequest.php index 3777cb7..e5ec7e3 100644 --- a/src/Request/UnifiedRequest.php +++ b/src/Request/UnifiedRequest.php @@ -9,14 +9,14 @@ use Guzzle\Http\Message\Header\HeaderCollection; use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\QueryString; -use Guzzle\Http\Url; -class UnifiedRequest +final class UnifiedRequest { private RequestInterface $wrapped; private ?string $userAgent = null; + /** @param array $params */ public function __construct(RequestInterface $wrapped, array $params = []) { $this->wrapped = $wrapped; @@ -34,7 +34,7 @@ public function getUserAgent(): ?string */ public function getBody(): ?EntityBodyInterface { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); + return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); } /** @@ -46,7 +46,7 @@ public function getBody(): ?EntityBodyInterface */ public function getPostField(string $field) { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); + return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, [$field]); } /** @@ -55,7 +55,7 @@ public function getPostField(string $field) */ public function getPostFields(): QueryString { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); + return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); } /** @@ -65,7 +65,7 @@ public function getPostFields(): QueryString */ public function getPostFiles(): array { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); + return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); } /** @@ -77,7 +77,7 @@ public function getPostFiles(): array */ public function getPostFile(string $fieldName): ?array { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); + return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, [$fieldName]); } /** @@ -258,7 +258,11 @@ public function getCookie(string $name): ?string return $this->wrapped->getCookie($name); } - protected function invokeWrappedIfEntityEnclosed($method, array $params = []) + /** + * @param array $params + * @return mixed + */ + protected function invokeWrappedIfEntityEnclosed(string $method, array $params = []) { if (!$this->wrapped instanceof EntityEnclosingRequestInterface) { throw new BadMethodCallException( @@ -275,12 +279,15 @@ protected function invokeWrappedIfEntityEnclosed($method, array $params = []) return call_user_func_array([$this->wrapped, $method], $params); } + /** @param array $params */ private function init(array $params): void { foreach ($params as $property => $value) { - if (property_exists($this, $property)) { - $this->{$property} = $value; + if (!property_exists($this, $property)) { + continue; } + + $this->{$property} = $value; } } } diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index 93ea03f..f233c5a 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -12,7 +12,7 @@ class RequestCollectionFacade implements Countable { - private $client; + private ClientInterface $client; public function __construct(ClientInterface $client) { @@ -61,7 +61,7 @@ public function shift(): UnifiedRequest return $this->deleteRecordedRequest('/_request/first'); } - public function count() + public function count(): int { $response = $this->client ->get('/_request/count') @@ -89,13 +89,18 @@ private function parseRequestFromResponse(Response $response, string $path): Uni $params = $this->configureRequest( $request, $requestInfo['server'], - isset($requestInfo['enclosure']) ? $requestInfo['enclosure'] : [] + $requestInfo['enclosure'] ?? [] ); return new UnifiedRequest($request, $params); } - private function configureRequest(RequestInterface $request, array $server, array $enclosure) + /** + * @param array $server + * @param array $enclosure + * @return array + */ + private function configureRequest(RequestInterface $request, array $server, array $enclosure): array { if (isset($server['HTTP_HOST'])) { $request->setHost($server['HTTP_HOST']); @@ -106,7 +111,7 @@ private function configureRequest(RequestInterface $request, array $server, arra } if (isset($server['PHP_AUTH_USER'])) { - $request->setAuth($server['PHP_AUTH_USER'], isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : null); + $request->setAuth($server['PHP_AUTH_USER'], $server['PHP_AUTH_PW'] ?? null); } $params = []; @@ -122,7 +127,7 @@ private function configureRequest(RequestInterface $request, array $server, arra return $params; } - private function getRecordedRequest($path) + private function getRecordedRequest(string $path): UnifiedRequest { $response = $this->client ->get($path) @@ -131,7 +136,7 @@ private function getRecordedRequest($path) return $this->parseResponse($response, $path); } - private function deleteRecordedRequest($path) + private function deleteRecordedRequest(string $path): UnifiedRequest { $response = $this->client ->delete($path) @@ -140,9 +145,9 @@ private function deleteRecordedRequest($path) return $this->parseResponse($response, $path); } - private function parseResponse(Response $response, $path) + private function parseResponse(Response $response, string $path): UnifiedRequest { - $statusCode = $response->getStatusCode(); + $statusCode = (int) $response->getStatusCode(); if ($statusCode !== 200) { throw new UnexpectedValueException( @@ -154,7 +159,7 @@ private function parseResponse(Response $response, $path) ? $response->getContentType() : ''; - if (substr($contentType, 0, 10) !== 'text/plain') { + if (strpos($contentType, 'text/plain') !== 0) { throw new UnexpectedValueException( sprintf('Expected content type "text/plain" from "%s", got "%s"', $path, $contentType) ); diff --git a/src/RequestStorage.php b/src/RequestStorage.php index abe4ce0..532dbf5 100644 --- a/src/RequestStorage.php +++ b/src/RequestStorage.php @@ -5,22 +5,24 @@ class RequestStorage { - private $pid; + private int $pid; - private $directory; + private string $directory; - public function __construct($pid, $directory) + public function __construct(int $pid, string $directory) { $this->pid = $pid; $this->directory = $directory; } - public function store(Request $request, $name, $data): void + /** @param mixed $data */ + public function store(Request $request, string $name, $data): void { file_put_contents($this->getFileName($request, $name), serialize($data)); } - public function read(Request $request, $name) + /** @return mixed */ + public function read(Request $request, string $name) { $fileName = $this->getFileName($request, $name); @@ -31,31 +33,35 @@ public function read(Request $request, $name) return Util::deserialize(file_get_contents($fileName)); } - public function append(Request $request, $name, $data): void + /** @param mixed $data */ + public function append(Request $request, string $name, $data): void { $list = $this->read($request, $name); $list[] = $data; $this->store($request, $name, $list); } - public function prepend(Request $request, $name, $data): void + /** @param mixed $data */ + public function prepend(Request $request, string $name, $data): void { $list = $this->read($request, $name); array_unshift($list, $data); $this->store($request, $name, $list); } - private function getFileName(Request $request, $name) + private function getFileName(Request $request, string $name): string { return $this->directory . $this->pid . '-' . $name . '-' . $request->server->get('SERVER_PORT'); } - public function clear(Request $request, $name): void + public function clear(Request $request, string $name): void { $fileName = $this->getFileName($request, $name); - if (file_exists($fileName)) { - unlink($fileName); + if (!file_exists($fileName)) { + return; } + + unlink($fileName); } } diff --git a/src/Response/CallbackResponse.php b/src/Response/CallbackResponse.php index e9aeb58..c49d71e 100644 --- a/src/Response/CallbackResponse.php +++ b/src/Response/CallbackResponse.php @@ -5,6 +5,7 @@ class CallbackResponse extends Response { + /** @var callable */ private $callback; public function setCallback(callable $callback): void @@ -14,10 +15,12 @@ public function setCallback(callable $callback): void public function sendCallback(): void { - if ($this->callback) { - $callback = $this->callback; - $callback($this); + if (!$this->callback) { + return; } + + $callback = $this->callback; + $callback($this); } public function send(): void diff --git a/src/ResponseBuilder.php b/src/ResponseBuilder.php index 7434a31..e845ce3 100644 --- a/src/ResponseBuilder.php +++ b/src/ResponseBuilder.php @@ -4,11 +4,11 @@ use InterNations\Component\HttpMock\Response\CallbackResponse; use SuperClosure\SerializableClosure; use Closure; +use Symfony\Component\HttpFoundation\Response; -class ResponseBuilder +final class ResponseBuilder { private MockBuilder $mockBuilder; - private CallbackResponse $response; public function __construct(MockBuilder $mockBuilder) @@ -17,40 +17,40 @@ public function __construct(MockBuilder $mockBuilder) $this->response = new CallbackResponse(); } - public function statusCode($statusCode) + public function statusCode(int $statusCode): self { $this->response->setStatusCode($statusCode); return $this; } - public function body($body) + public function body(string $body): self { $this->response->setContent($body); return $this; } - public function callback(Closure $callback) + public function callback(Closure $callback): self { $this->response->setCallback(new SerializableClosure($callback)); return $this; } - public function header($header, $value) + public function header(string $header, string $value): self { $this->response->headers->set($header, $value); return $this; } - public function end() + public function end(): MockBuilder { return $this->mockBuilder; } - public function getResponse() + public function getResponse(): Response { return $this->response; } diff --git a/src/Server.php b/src/Server.php index ef10872..fc0eaa9 100644 --- a/src/Server.php +++ b/src/Server.php @@ -10,13 +10,13 @@ class Server extends Process { - private $port; + private int $port; - private $host; + private string $host; - private $client; + private ?Client $client = null; - public function __construct($port, $host) + public function __construct(int $port, string $host) { $this->port = $port; $this->host = $host; @@ -34,6 +34,7 @@ public function __construct($port, $host) $this->setTimeout(null); } + /** @param array $env */ public function start(callable $callback = null, array $env = []): void { parent::start($callback, $env); @@ -41,17 +42,21 @@ public function start(callable $callback = null, array $env = []): void $this->pollWait(); } - public function stop($timeout = 10, $signal = null) + /** + * @param int|float $timeout + * @param int $signal + */ + public function stop($timeout = 10, $signal = null): ?int { return parent::stop($timeout, $signal); } - public function getClient() + public function getClient(): Client { return $this->client ?: $this->client = $this->createClient(); } - private function createClient() + private function createClient(): Client { $client = new Client($this->getBaseUrl()); $client->getEventDispatcher()->addListener( @@ -64,18 +69,18 @@ static function (Event $event): void { return $client; } - public function getBaseUrl() + public function getBaseUrl(): string { return sprintf('http://%s', $this->getConnectionString()); } - public function getConnectionString() + public function getConnectionString(): string { return sprintf('%s:%d', $this->host, $this->port); } /** - * @param Expectation[] $expectations + * @param array $expectations * @throws RuntimeException */ public function setUp(array $expectations): void @@ -120,17 +125,17 @@ private function pollWait(): void } } - public function getIncrementalErrorOutput() + public function getIncrementalErrorOutput(): string { return self::cleanErrorOutput(parent::getIncrementalErrorOutput()); } - public function getErrorOutput() + public function getErrorOutput(): string { return self::cleanErrorOutput(parent::getErrorOutput()); } - private static function cleanErrorOutput($output) + private static function cleanErrorOutput(string $output): string { if (!trim($output)) { return ''; @@ -143,15 +148,18 @@ private static function cleanErrorOutput($output) continue; } - if (!self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { - $errorLines[] = $line; + if (self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { + continue; } + + $errorLines[] = $line; } return $errorLines ? implode(PHP_EOL, $errorLines) : ''; } - private static function stringEndsWithAny($haystack, array $needles) + /** @param list $needles */ + private static function stringEndsWithAny(string $haystack, array $needles): bool { foreach ($needles as $needle) { if (substr($haystack, (-1 * strlen($needle))) === $needle) { diff --git a/src/Util.php b/src/Util.php index 6437a41..998db3d 100644 --- a/src/Util.php +++ b/src/Util.php @@ -5,9 +5,10 @@ final class Util { - public static function deserialize($string) + /** @return mixed */ + public static function deserialize(string $string) { - $result = static::silentDeserialize($string); + $result = self::silentDeserialize($string); if ($result === false) { throw new UnexpectedValueException('Cannot deserialize string'); @@ -16,7 +17,8 @@ public static function deserialize($string) return $result; } - public static function silentDeserialize($string) + /** @return mixed */ + public static function silentDeserialize(string $string) { // @codingStandardsIgnoreStart return @unserialize($string); diff --git a/src/app.php b/src/app.php index 0dd46b3..032f3fb 100644 --- a/src/app.php +++ b/src/app.php @@ -50,7 +50,15 @@ static function (Request $request) use ($app) { $matcher = []; if ($request->request->has('matcher')) { - $matcher = Util::silentDeserialize($request->request->get('matcher')); + $matcherParameter = $request->request->get('matcher'); + if (!is_string($matcherParameter)) { + return new Response( + 'POST data key "matcher" must be a serialized list of closures', + Response::HTTP_EXPECTATION_FAILED + ); + } + + $matcher = Util::silentDeserialize($matcherParameter); $validator = static function ($closure) { return is_callable($closure); }; diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index c8d8ebc..9d4efa9 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -6,11 +6,9 @@ use Guzzle\Http\Client; use Guzzle\Http\Message\RequestFactory; use Guzzle\Http\Message\Response as GuzzleResponse; -use Guzzle\Http\Message\EntityEnclosingRequest; use SuperClosure\SerializableClosure; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Process\Process; /** * @large @@ -18,36 +16,30 @@ */ class AppIntegrationTest extends AbstractTestCase { - /** - * @var Server - */ - private static $server1; + private static Server $server1; - /** - * @var Client - */ - private $client; + private Client $client; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { static::$server1 = new Server(HTTP_MOCK_PORT, HTTP_MOCK_HOST); static::$server1->start(); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { static::assertSame('', (string) static::$server1->getOutput(), (string) static::$server1->getOutput()); static::assertSame('', (string) static::$server1->getErrorOutput(), (string) static::$server1->getErrorOutput()); static::$server1->stop(); } - public function setUp() + public function setUp(): void { static::$server1->clean(); $this->client = static::$server1->getClient(); } - public function testSimpleUseCase() + public function testSimpleUseCase(): void { $response = $this->client->post( '/_expectation', @@ -56,7 +48,7 @@ public function testSimpleUseCase() [ static function ($request) { return $request instanceof Request; - } + }, ], new Response('fake body', 200) ) @@ -77,7 +69,7 @@ static function ($request) { $this->assertSame('post=data', (string) $request->getBody()); } - public function testRecording() + public function testRecording(): void { $this->client->delete('/_all')->send(); @@ -132,7 +124,7 @@ public function testRecording() $this->assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); } - public function testErrorHandling() + public function testErrorHandling(): void { $this->client->delete('/_all')->send(); @@ -157,7 +149,7 @@ public function testErrorHandling() $this->assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } - public function testServerParamsAreRecorded() + public function testServerParamsAreRecorded(): void { $this->client ->setUserAgent('CUSTOM UA') @@ -176,7 +168,7 @@ public function testServerParamsAreRecorded() $this->assertSame('CUSTOM UA', $latestRequest['server']['HTTP_USER_AGENT']); } - public function testNewestExpectationsAreFirstEvaluated() + public function testNewestExpectationsAreFirstEvaluated(): void { $this->client->post( '/_expectation', @@ -185,7 +177,7 @@ public function testNewestExpectationsAreFirstEvaluated() [ static function ($request) { return $request instanceof Request; - } + }, ], new Response('first', 200) ) @@ -199,7 +191,7 @@ static function ($request) { [ static function ($request) { return $request instanceof Request; - } + }, ], new Response('second', 200) ) @@ -207,7 +199,7 @@ static function ($request) { $this->assertSame('second', $this->client->get('/')->send()->getBody(true)); } - public function testServerLogsAreNotInErrorOutput() + public function testServerLogsAreNotInErrorOutput(): void { $this->client->delete('/_all'); diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index b6d746e..ae1be24 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -5,12 +5,12 @@ class Request extends BaseRequest { - public function setRequestUri($requestUri) + public function setRequestUri($requestUri): void { $this->requestUri = $requestUri; } - public function setContent($content) + public function setContent($content): void { $this->content = $content; } diff --git a/tests/Matcher/ExtractorFactoryTest.php b/tests/Matcher/ExtractorFactoryTest.php index 3f5f8f7..ceaa323 100644 --- a/tests/Matcher/ExtractorFactoryTest.php +++ b/tests/Matcher/ExtractorFactoryTest.php @@ -4,23 +4,21 @@ use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\Testing\AbstractTestCase; use Symfony\Component\HttpFoundation\Request; -use PHPUnit\Framework\MockObject\MockObject; class ExtractorFactoryTest extends AbstractTestCase { - /** @var ExtractorFactory */ - private $extractorFactory; + private ExtractorFactory $extractorFactory; /** @var Request|MockObject */ private $request; - public function setUp() + public function setUp(): void { $this->extractorFactory = new ExtractorFactory(); $this->request = $this->createMock('Symfony\Component\HttpFoundation\Request'); } - public function testGetMethod() + public function testGetMethod(): void { $this->request ->expects($this->once()) @@ -31,7 +29,7 @@ public function testGetMethod() $this->assertSame('POST', $extractor($this->request)); } - public function testGetPath() + public function testGetPath(): void { $this->request ->expects($this->once()) @@ -42,7 +40,7 @@ public function testGetPath() $this->assertSame('/foo/bar', $extractor($this->request)); } - public function testGetPathWithBasePath() + public function testGetPathWithBasePath(): void { $this->request ->expects($this->once()) @@ -55,7 +53,7 @@ public function testGetPathWithBasePath() $this->assertSame('/bar', $extractor($this->request)); } - public function testGetPathWithBasePathTrailingSlash() + public function testGetPathWithBasePathTrailingSlash(): void { $this->request ->expects($this->once()) @@ -68,7 +66,7 @@ public function testGetPathWithBasePathTrailingSlash() $this->assertSame('/bar', $extractor($this->request)); } - public function testGetPathWithBasePathThatDoesNotMatch() + public function testGetPathWithBasePathThatDoesNotMatch(): void { $this->request ->expects($this->once()) @@ -81,7 +79,7 @@ public function testGetPathWithBasePathThatDoesNotMatch() $this->assertSame('', $extractor($this->request)); } - public function testGetHeaderWithExistingHeader() + public function testGetHeaderWithExistingHeader(): void { $request = new Request( [], @@ -98,7 +96,7 @@ public function testGetHeaderWithExistingHeader() $this->assertSame('application/json', $extractor($request)); } - public function testGetHeaderWithNonExistingHeader() + public function testGetHeaderWithNonExistingHeader(): void { $request = new Request( [], @@ -115,7 +113,7 @@ public function testGetHeaderWithNonExistingHeader() $this->assertNull($extractor($request)); } - public function testHeaderExistsWithExistingHeader() + public function testHeaderExistsWithExistingHeader(): void { $request = new Request( [], @@ -132,7 +130,7 @@ public function testHeaderExistsWithExistingHeader() $this->assertTrue($extractor($request)); } - public function testHeaderExistsWithNonExistingHeader() + public function testHeaderExistsWithNonExistingHeader(): void { $request = new Request( [], diff --git a/tests/Matcher/StringMatcherTest.php b/tests/Matcher/StringMatcherTest.php index 32df60c..fab4b12 100644 --- a/tests/Matcher/StringMatcherTest.php +++ b/tests/Matcher/StringMatcherTest.php @@ -7,7 +7,7 @@ class StringMatcherTest extends AbstractTestCase { - public function testConversionToString() + public function testConversionToString(): void { $matcher = new StringMatcher('0'); $matcher->setExtractor(static function() { diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 5e06a54..9308438 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -1,7 +1,6 @@ matches = new MatcherFactory(); $this->builder = new MockBuilder($this->matches, new ExtractorFactory()); @@ -36,12 +32,12 @@ public function setUp() $this->server->clean(); } - public function tearDown() + public function tearDown(): void { $this->server->stop(); } - public function testCreateExpectation() + public function testCreateExpectation(): void { $builder = $this->builder ->when() @@ -96,7 +92,7 @@ public function testCreateExpectation() $this->assertContains('CLOSURE MATCHER: POST /foo', $this->server->getErrorOutput()); } - public function testCreateTwoExpectationsAfterEachOther() + public function testCreateTwoExpectationsAfterEachOther(): void { $this->builder ->when() @@ -124,7 +120,7 @@ public function testCreateTwoExpectationsAfterEachOther() $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); } - public function testCreateSuccessiveExpectationsOnSameWhen() + public function testCreateSuccessiveExpectationsOnSameWhen(): void { $this->builder ->first() @@ -155,7 +151,7 @@ public function testCreateSuccessiveExpectationsOnSameWhen() $this->assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } - public function testCreateSuccessiveExpectationsWithAny() + public function testCreateSuccessiveExpectationsWithAny(): void { $this->builder ->first() @@ -186,7 +182,7 @@ public function testCreateSuccessiveExpectationsWithAny() $this->assertSame('any', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } - public function testCreateSuccessiveExpectationsInUnexpectedOrder() + public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void { $this->builder ->second() @@ -209,7 +205,7 @@ public function testCreateSuccessiveExpectationsInUnexpectedOrder() $this->assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } - public function testCreateSuccessiveExpectationsWithOnce() + public function testCreateSuccessiveExpectationsWithOnce(): void { $this->builder ->first() diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index baad498..873c8e0 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -2,32 +2,32 @@ namespace InterNations\Component\HttpMock\Tests\PHPUnit; use InterNations\Component\Testing\AbstractTestCase; -use InterNations\Component\HttpMock\PHPUnit\HttpMockTrait; +use InterNations\Component\HttpMock\PHPUnit\HttpMock; use Symfony\Component\HttpFoundation\Response; use PHPUnit\Framework\TestCase; /** @large */ class HttpMockMultiPHPUnitIntegrationTest extends AbstractTestCase { - use HttpMockTrait; + use HttpMock; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { static::setUpHttpMockBeforeClass(null, null, null, 'firstNamedServer'); static::setUpHttpMockBeforeClass(static::getHttpMockDefaultPort() + 1, null, null, 'secondNamedServer'); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { static::tearDownHttpMockAfterClass(); } - public function setUp() + public function setUp(): void { $this->setUpHttpMock(); } - public function tearDown() + public function tearDown(): void { $this->tearDownHttpMock(); } @@ -38,12 +38,12 @@ public static function getPaths() [ '/foo', '/bar', - ] + ], ]; } /** @dataProvider getPaths */ - public function testSimpleRequest($path) + public function testSimpleRequest($path): void { $this->http['firstNamedServer']->mock ->when() @@ -87,11 +87,11 @@ public function testSimpleRequest($path) $this->http['firstNamedServer']->requests->pop(); } - public function testErrorLogOutput() + public function testErrorLogOutput(): void { $this->http['firstNamedServer']->mock ->when() - ->callback(static function () {error_log('error output');}) + ->callback(static function (): void {error_log('error output');}) ->then() ->end(); $this->http['firstNamedServer']->setUp(); @@ -107,26 +107,26 @@ public function testErrorLogOutput() } } - public function testFailedRequest() + public function testFailedRequest(): void { $response = $this->http['firstNamedServer']->client->get('/foo')->send(); $this->assertSame(404, $response->getStatusCode()); $this->assertSame('No matching expectation found', (string) $response->getBody()); } - public function testStopServer() + public function testStopServer(): void { $this->http['firstNamedServer']->server->stop(); } /** @depends testStopServer */ - public function testHttpServerIsRestartedIfATestStopsIt() + public function testHttpServerIsRestartedIfATestStopsIt(): void { $response = $this->http['firstNamedServer']->client->get('/')->send(); $this->assertSame(404, $response->getStatusCode()); } - public function testLimitDurationOfAResponse() + public function testLimitDurationOfAResponse(): void { $this->http['firstNamedServer']->mock ->once() @@ -174,19 +174,19 @@ public function testLimitDurationOfAResponse() $this->assertSame(200, $thirdResponse->getStatusCode()); } - public function testCallbackOnResponse() + public function testCallbackOnResponse(): void { $this->http['firstNamedServer']->mock ->when() ->methodIs('POST') ->then() - ->callback(static function(Response $response) {$response->setContent('CALLBACK');}) + ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http['firstNamedServer']->setUp(); $this->assertSame('CALLBACK', $this->http['firstNamedServer']->client->post('/')->send()->getBody(true)); } - public function testComplexResponse() + public function testComplexResponse(): void { $this->http['firstNamedServer']->mock ->when() @@ -205,7 +205,7 @@ public function testComplexResponse() $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); } - public function testPutRequest() + public function testPutRequest(): void { $this->http['firstNamedServer']->mock ->when() @@ -224,7 +224,7 @@ public function testPutRequest() $this->assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->getPostField('put-key')); } - public function testPostRequest() + public function testPostRequest(): void { $this->http['firstNamedServer']->mock ->when() @@ -243,7 +243,7 @@ public function testPostRequest() $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); } - public function testFatalError() + public function testFatalError(): void { if (version_compare(PHP_VERSION, '7.0', '<')) { $this->markTestSkipped('Comment in to test if fatal errors are properly handled'); diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index 8cc8199..b8c3f2e 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -2,34 +2,34 @@ namespace InterNations\Component\HttpMock\Tests\PHPUnit; use InterNations\Component\Testing\AbstractTestCase; -use InterNations\Component\HttpMock\PHPUnit\HttpMockTrait; +use InterNations\Component\HttpMock\PHPUnit\HttpMock; /** @large */ class HttpMockPHPUnitIntegrationBasePathTest extends AbstractTestCase { - use HttpMockTrait; + use HttpMock; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { static::setUpHttpMockBeforeClass(null, null, '/custom-base-path'); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { static::tearDownHttpMockAfterClass(); } - public function setUp() + public function setUp(): void { $this->setUpHttpMock(); } - public function tearDown() + public function tearDown(): void { $this->tearDownHttpMock(); } - public function testSimpleRequest() + public function testSimpleRequest(): void { $this->http->mock ->when() diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 39a8518..dd05453 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -1,7 +1,7 @@ setUpHttpMock(); } - public function tearDown() + public function tearDown(): void { $this->tearDownHttpMock(); } @@ -38,12 +38,12 @@ public static function getPaths() [ '/foo', '/bar', - ] + ], ]; } /** @dataProvider getPaths */ - public function testSimpleRequest($path) + public function testSimpleRequest($path): void { $this->http->mock ->when() @@ -87,11 +87,11 @@ public function testSimpleRequest($path) $this->http->requests->pop(); } - public function testErrorLogOutput() + public function testErrorLogOutput(): void { $this->http->mock ->when() - ->callback(static function () {error_log('error output');}) + ->callback(static function (): void {error_log('error output');}) ->then() ->end(); $this->http->setUp(); @@ -107,26 +107,26 @@ public function testErrorLogOutput() } } - public function testFailedRequest() + public function testFailedRequest(): void { $response = $this->http->client->get('/foo')->send(); $this->assertSame(404, $response->getStatusCode()); $this->assertSame('No matching expectation found', (string) $response->getBody()); } - public function testStopServer() + public function testStopServer(): void { $this->http->server->stop(); } /** @depends testStopServer */ - public function testHttpServerIsRestartedIfATestStopsIt() + public function testHttpServerIsRestartedIfATestStopsIt(): void { $response = $this->http->client->get('/')->send(); $this->assertSame(404, $response->getStatusCode()); } - public function testLimitDurationOfAResponse() + public function testLimitDurationOfAResponse(): void { $this->http->mock ->once() @@ -174,19 +174,19 @@ public function testLimitDurationOfAResponse() $this->assertSame(200, $thirdResponse->getStatusCode()); } - public function testCallbackOnResponse() + public function testCallbackOnResponse(): void { $this->http->mock ->when() ->methodIs('POST') ->then() - ->callback(static function(Response $response) {$response->setContent('CALLBACK');}) + ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http->setUp(); $this->assertSame('CALLBACK', $this->http->client->post('/')->send()->getBody(true)); } - public function testComplexResponse() + public function testComplexResponse(): void { $this->http->mock ->when() @@ -205,7 +205,7 @@ public function testComplexResponse() $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); } - public function testPutRequest() + public function testPutRequest(): void { $this->http->mock ->when() @@ -224,7 +224,7 @@ public function testPutRequest() $this->assertSame('put-value', $this->http->requests->latest()->getPostField('put-key')); } - public function testPostRequest() + public function testPostRequest(): void { $this->http->mock ->when() @@ -243,7 +243,7 @@ public function testPostRequest() $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); } - public function testCountRequests() + public function testCountRequests(): void { $this->http->mock ->when() @@ -258,12 +258,12 @@ public function testCountRequests() $this->assertCount(1, $this->http->requests); } - public function testMatchQueryString() + public function testMatchQueryString(): void { $this->http->mock ->when() ->callback( - function (Request $request) { + static function (Request $request) { return $request->query->has('key1'); } ) @@ -279,7 +279,7 @@ function (Request $request) { $this->assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->send()->getStatusCode()); } - public function testMatchRegex() + public function testMatchRegex(): void { $this->http->mock ->when() @@ -293,7 +293,7 @@ public function testMatchRegex() $this->assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); } - public function testMatchQueryParams() + public function testMatchQueryParams(): void { $this->http->mock ->when() @@ -326,7 +326,7 @@ public function testMatchQueryParams() ); } - public function testFatalError() + public function testFatalError(): void { if (version_compare(PHP_VERSION, '7.0', '<')) { $this->markTestSkipped('Comment in to test if fatal errors are properly handled'); diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php index 0d3be75..e9d2d1a 100644 --- a/tests/Request/UnifiedRequestTest.php +++ b/tests/Request/UnifiedRequestTest.php @@ -3,14 +3,11 @@ use Guzzle\Common\Collection; use Guzzle\Http\EntityBody; -use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Message\Header; use Guzzle\Http\Message\Header\HeaderCollection; use Guzzle\Http\QueryString; use InterNations\Component\HttpMock\Request\UnifiedRequest; use InterNations\Component\Testing\AbstractTestCase; -use Guzzle\Http\Message\RequestInterface; -use PHPUnit\Framework\MockObject\MockObject; class UnifiedRequestTest extends AbstractTestCase { @@ -20,13 +17,11 @@ class UnifiedRequestTest extends AbstractTestCase /** @var EntityEnclosingRequestInterface|MockObject */ private $wrappedEntityEnclosingRequest; - /** @var UnifiedRequest */ - private $unifiedRequest; + private UnifiedRequest $unifiedRequest; - /** @var UnifiedRequest */ - private $unifiedEnclosingEntityRequest; + private UnifiedRequest $unifiedEnclosingEntityRequest; - public function setUp() + public function setUp(): void { $this->wrappedRequest = $this->createMock('Guzzle\Http\Message\RequestInterface'); $this->wrappedEntityEnclosingRequest = $this->createMock('Guzzle\Http\Message\EntityEnclosingRequestInterface'); @@ -72,7 +67,7 @@ public static function provideEntityEnclosingInterfaceMethods() } /** @dataProvider provideMethods */ - public function testMethodsFromRequestInterface($method, array $params = [], $returnValue = 'REQ') + public function testMethodsFromRequestInterface($method, array $params = [], $returnValue = 'REQ'): void { $this->wrappedRequest ->expects($this->once()) @@ -94,7 +89,11 @@ public function testMethodsFromRequestInterface($method, array $params = [], $re } /** @dataProvider provideEntityEnclosingInterfaceMethods */ - public function testEntityEnclosingInterfaceMethods($method, array $params = [], $returnValue = 'Return Value') + public function testEntityEnclosingInterfaceMethods( + $method, + array $params = [], + $returnValue = 'Return Value' + ): void { $this->wrappedEntityEnclosingRequest ->expects($this->once()) @@ -129,7 +128,7 @@ public function testEntityEnclosingInterfaceMethods($method, array $params = [], call_user_func_array([$this->unifiedRequest, $method], $params); } - public function testUserAgent() + public function testUserAgent(): void { $this->assertNull($this->unifiedRequest->getUserAgent()); diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index e111263..d5090b4 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -1,12 +1,10 @@ client = $this->createMock('Guzzle\Http\ClientInterface'); $this->facade = new RequestCollectionFacade($this->client); @@ -41,7 +37,7 @@ public static function provideMethodAndUrls() } /** @dataProvider provideMethodAndUrls */ - public function testRequestingLatestRequest($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestingLatestRequest($method, $path, array $args = [], $httpMethod = 'get'): void { $this->mockClient($path, $this->createSimpleResponse(), $httpMethod); @@ -53,7 +49,7 @@ public function testRequestingLatestRequest($method, $path, array $args = [], $h } /** @dataProvider provideMethodAndUrls */ - public function testRequestLatestResponseWithHttpAuth($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestLatestResponseWithHttpAuth($method, $path, array $args = [], $httpMethod = 'get'): void { $this->mockClient($path, $this->createComplexResponse(), $httpMethod); @@ -70,7 +66,7 @@ public function testRequestLatestResponseWithHttpAuth($method, $path, array $arg } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponse_InvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get'): void { $this->mockClient($path, $this->createResponseWithInvalidStatusCode(), $httpMethod); @@ -81,7 +77,7 @@ public function testRequestResponse_InvalidStatusCode($method, $path, array $arg } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_EmptyContentType($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponse_EmptyContentType($method, $path, array $args = [], $httpMethod = 'get'): void { $this->mockClient($path, $this->createResponseWithEmptyContentType(), $httpMethod); @@ -92,7 +88,7 @@ public function testRequestResponse_EmptyContentType($method, $path, array $args } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidContentType($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponse_InvalidContentType($method, $path, array $args = [], $httpMethod = 'get'): void { $this->mockClient($path, $this->createResponseWithInvalidContentType(), $httpMethod); @@ -103,7 +99,12 @@ public function testRequestResponse_InvalidContentType($method, $path, array $ar } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_DeserializationError($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponse_DeserializationError( + $method, + $path, + array $args = [], + $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createResponseThatCannotBeDeserialized(), $httpMethod); @@ -113,7 +114,7 @@ public function testRequestResponse_DeserializationError($method, $path, array $ call_user_func_array([$this->facade, $method], $args); } - private function mockClient($path, Response $response, $method) + private function mockClient($path, Response $response, $method): void { $this->client ->expects($this->once()) From d070626dc99d9fa74585f16e85d6b8808881174b Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Mon, 10 May 2021 21:43:03 +0200 Subject: [PATCH 04/38] Next --- tests/AppIntegrationTest.php | 10 +- tests/Fixtures/Request.php | 4 +- .../HttpMockMultiPHPUnitIntegrationTest.php | 10 +- .../HttpMockPHPUnitIntegrationTest.php | 10 +- tests/Request/UnifiedRequestTest.php | 21 +++-- tests/RequestCollectionFacadeTest.php | 91 ++++++++++++------- 6 files changed, 89 insertions(+), 57 deletions(-) diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index 9d4efa9..46eaa5a 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -1,6 +1,8 @@ clearErrorOutput(); } - private function parseRequestFromResponse(GuzzleResponse $response) + private function parseRequestFromResponse(GuzzleResponse $response): RequestInterface { $body = unserialize($response->getBody()); return RequestFactory::getInstance()->fromMessage($body['request']); } - private function createExpectationParams(array $closures, Response $response) + /** + * @param list $closures + * @return array{matcher: string, response: string} + */ + private function createExpectationParams(array $closures, Response $response): array { foreach ($closures as $index => $closure) { $closures[$index] = new SerializableClosure($closure); diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index ae1be24..6be38fe 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -5,12 +5,12 @@ class Request extends BaseRequest { - public function setRequestUri($requestUri): void + public function setRequestUri(string $requestUri): void { $this->requestUri = $requestUri; } - public function setContent($content): void + public function setContent(string $content): void { $this->content = $content; } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 873c8e0..38c7925 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -32,18 +32,16 @@ public function tearDown(): void $this->tearDownHttpMock(); } - public static function getPaths() + public static function getPaths(): array { return [ - [ - '/foo', - '/bar', - ], + ['/foo'], + ['/bar'], ]; } /** @dataProvider getPaths */ - public function testSimpleRequest($path): void + public function testSimpleRequest(string $path): void { $this->http['firstNamedServer']->mock ->when() diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index dd05453..6745c32 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -32,18 +32,16 @@ public function tearDown(): void $this->tearDownHttpMock(); } - public static function getPaths() + public static function getPaths(): array { return [ - [ - '/foo', - '/bar', - ], + ['/foo'], + ['/bar'], ]; } /** @dataProvider getPaths */ - public function testSimpleRequest($path): void + public function testSimpleRequest(string $path): void { $this->http->mock ->when() diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php index e9d2d1a..aa80bdc 100644 --- a/tests/Request/UnifiedRequestTest.php +++ b/tests/Request/UnifiedRequestTest.php @@ -3,11 +3,14 @@ use Guzzle\Common\Collection; use Guzzle\Http\EntityBody; +use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Message\Header; use Guzzle\Http\Message\Header\HeaderCollection; +use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\QueryString; use InterNations\Component\HttpMock\Request\UnifiedRequest; use InterNations\Component\Testing\AbstractTestCase; +use PHPUnit\Framework\MockObject\MockObject; class UnifiedRequestTest extends AbstractTestCase { @@ -23,13 +26,13 @@ class UnifiedRequestTest extends AbstractTestCase public function setUp(): void { - $this->wrappedRequest = $this->createMock('Guzzle\Http\Message\RequestInterface'); - $this->wrappedEntityEnclosingRequest = $this->createMock('Guzzle\Http\Message\EntityEnclosingRequestInterface'); + $this->wrappedRequest = $this->createMock(RequestInterface::class); + $this->wrappedEntityEnclosingRequest = $this->createMock(EntityEnclosingRequestInterface::class); $this->unifiedRequest = new UnifiedRequest($this->wrappedRequest); $this->unifiedEnclosingEntityRequest = new UnifiedRequest($this->wrappedEntityEnclosingRequest); } - public static function provideMethods() + public static function provideMethods(): array { return [ ['getParams', [], new Collection()], @@ -55,7 +58,7 @@ public static function provideMethods() ]; } - public static function provideEntityEnclosingInterfaceMethods() + public static function provideEntityEnclosingInterfaceMethods(): array { return [ ['getBody', [], EntityBody::fromString('foo')], @@ -72,7 +75,7 @@ public function testMethodsFromRequestInterface($method, array $params = [], $re $this->wrappedRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue($returnValue)) + ->willReturn($returnValue) ->with(...$params); $this->assertSame($returnValue, call_user_func_array([$this->unifiedRequest, $method], $params)); @@ -80,7 +83,7 @@ public function testMethodsFromRequestInterface($method, array $params = [], $re $this->wrappedEntityEnclosingRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue($returnValue)) + ->willReturn($returnValue) ->with(...$params); $this->assertSame( $returnValue, @@ -98,7 +101,7 @@ public function testEntityEnclosingInterfaceMethods( $this->wrappedEntityEnclosingRequest ->expects($this->once()) ->method($method) - ->will($this->returnValue($returnValue)) + ->willReturn($returnValue) ->with(...$params); $this->assertSame( @@ -109,11 +112,11 @@ public function testEntityEnclosingInterfaceMethods( $this->wrappedRequest ->expects($this->any()) ->method('getMethod') - ->will($this->returnValue('METHOD')); + ->willReturn('METHOD'); $this->wrappedRequest ->expects($this->any()) ->method('getPath') - ->will($this->returnValue('/foo')); + ->willReturn('/foo'); $this->expectException('BadMethodCallException'); diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index d5090b4..bd21c12 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -1,11 +1,13 @@ request->setClient($this->client); } - public static function provideMethodAndUrls() + public static function provideMethodAndUrls(): array { return [ ['latest', '/_request/last'], @@ -37,36 +39,51 @@ public static function provideMethodAndUrls() } /** @dataProvider provideMethodAndUrls */ - public function testRequestingLatestRequest($method, $path, array $args = [], $httpMethod = 'get'): void + public function testRequestingLatestRequest( + string $method, + string $path, + array $args = [], + string $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createSimpleResponse(), $httpMethod); $request = call_user_func_array([$this->facade, $method], $args); - $this->assertSame('POST', $request->getMethod()); - $this->assertSame('/foo', $request->getPath()); - $this->assertSame('RECORDED=1', (string) $request->getBody()); + self::assertSame('POST', $request->getMethod()); + self::assertSame('/foo', $request->getPath()); + self::assertSame('RECORDED=1', (string) $request->getBody()); } /** @dataProvider provideMethodAndUrls */ - public function testRequestLatestResponseWithHttpAuth($method, $path, array $args = [], $httpMethod = 'get'): void + public function testRequestLatestResponseWithHttpAuth( + string $method, + string $path, + array $args = [], + string $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createComplexResponse(), $httpMethod); $request = call_user_func_array([$this->facade, $method], $args); - $this->assertSame('POST', $request->getMethod()); - $this->assertSame('/foo', $request->getPath()); - $this->assertSame('RECORDED=1', (string) $request->getBody()); - $this->assertSame('host', $request->getHost()); - $this->assertSame(1234, $request->getPort()); - $this->assertSame('username', $request->getUsername()); - $this->assertSame('password', $request->getPassword()); - $this->assertSame('CUSTOM UA', $request->getUserAgent()); + self::assertSame('POST', $request->getMethod()); + self::assertSame('/foo', $request->getPath()); + self::assertSame('RECORDED=1', (string) $request->getBody()); + self::assertSame('host', $request->getHost()); + self::assertSame(1234, $request->getPort()); + self::assertSame('username', $request->getUsername()); + self::assertSame('password', $request->getPassword()); + self::assertSame('CUSTOM UA', $request->getUserAgent()); } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get'): void + public function testRequestResponseWithInvalidStatusCode( + string $method, + string $path, + array $args = [], + string $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createResponseWithInvalidStatusCode(), $httpMethod); @@ -77,7 +94,12 @@ public function testRequestResponse_InvalidStatusCode($method, $path, array $arg } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_EmptyContentType($method, $path, array $args = [], $httpMethod = 'get'): void + public function testRequestResponseWithEmptyContentType( + string $method, + string $path, + array $args = [], + string $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createResponseWithEmptyContentType(), $httpMethod); @@ -88,7 +110,12 @@ public function testRequestResponse_EmptyContentType($method, $path, array $args } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidContentType($method, $path, array $args = [], $httpMethod = 'get'): void + public function testRequestResponseWithInvalidContentType( + string $method, + string $path, + array $args = [], + string $httpMethod = 'get' + ): void { $this->mockClient($path, $this->createResponseWithInvalidContentType(), $httpMethod); @@ -99,11 +126,11 @@ public function testRequestResponse_InvalidContentType($method, $path, array $ar } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_DeserializationError( - $method, - $path, + public function testRequestResponseWithDeserializationError( + string $method, + string $path, array $args = [], - $httpMethod = 'get' + string $httpMethod = 'get' ): void { $this->mockClient($path, $this->createResponseThatCannotBeDeserialized(), $httpMethod); @@ -114,22 +141,22 @@ public function testRequestResponse_DeserializationError( call_user_func_array([$this->facade, $method], $args); } - private function mockClient($path, Response $response, $method): void + private function mockClient(string $path, Response $response, string $method): void { $this->client - ->expects($this->once()) + ->expects(self::once()) ->method($method) ->with($path) - ->will($this->returnValue($this->request)); + ->willReturn($this->request); $this->client - ->expects($this->once()) + ->expects(self::once()) ->method('send') ->with($this->request) - ->will($this->returnValue($response)); + ->willReturn($response); } - private function createSimpleResponse() + private function createSimpleResponse(): Response { $recordedRequest = new TestRequest(); $recordedRequest->setMethod('POST'); @@ -148,7 +175,7 @@ private function createSimpleResponse() ); } - private function createComplexResponse() + private function createComplexResponse(): Response { $recordedRequest = new TestRequest(); $recordedRequest->setMethod('POST'); @@ -176,22 +203,22 @@ private function createComplexResponse() ); } - private function createResponseWithInvalidStatusCode() + private function createResponseWithInvalidStatusCode(): Response { return new Response(404); } - private function createResponseWithInvalidContentType() + private function createResponseWithInvalidContentType(): Response { return new Response(200, ['Content-Type' => 'text/html']); } - private function createResponseWithEmptyContentType() + private function createResponseWithEmptyContentType(): Response { return new Response(200, []); } - private function createResponseThatCannotBeDeserialized() + private function createResponseThatCannotBeDeserialized(): Response { return new Response(200, ['Content-Type' => 'text/plain'], 'invalid response'); } From 4b7478d54ba8238866902a5fb540f5dc1feba8a9 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:14:24 +0200 Subject: [PATCH 05/38] Final --- phpcs.xml.dist | 3 +- src/Expectation.php | 3 -- src/PHPUnit/HttpMockFacadeMap.php | 14 ++++++-- src/PHPUnit/HttpMockTrait.php | 2 +- src/Request/UnifiedRequest.php | 10 +++--- src/Server.php | 2 +- .../HttpMockMultiPHPUnitIntegrationTest.php | 1 + .../HttpMockPHPUnitIntegrationTest.php | 1 + tests/Request/UnifiedRequestTest.php | 22 ++++++++---- tests/RequestCollectionFacadeTest.php | 35 ++++++++++++++----- 10 files changed, 65 insertions(+), 28 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index c10c59a..92c9d99 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -17,13 +17,12 @@ - - + diff --git a/src/Expectation.php b/src/Expectation.php index c1d3fe5..abc4c3a 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -14,11 +14,8 @@ class Expectation private array $matcher = []; private MatcherFactory $matcherFactory; private ResponseBuilder $responseBuilder; - private Closure $limiter; - private ExtractorFactory $extractorFactory; - private int $priority; public function __construct( diff --git a/src/PHPUnit/HttpMockFacadeMap.php b/src/PHPUnit/HttpMockFacadeMap.php index c6e9c01..602ac4d 100644 --- a/src/PHPUnit/HttpMockFacadeMap.php +++ b/src/PHPUnit/HttpMockFacadeMap.php @@ -17,6 +17,10 @@ public function __construct(array $facadeMap) $this->facadeMap = $facadeMap; } + /** + * @param int|string $offset + * @return mixed + */ public function offsetGet($offset) { if (!$this->offsetExists($offset)) { @@ -26,17 +30,23 @@ public function offsetGet($offset) return $this->facadeMap[$offset]; } + /** @param int|string $offset */ public function offsetExists($offset): bool { return isset($this->facadeMap[$offset]); } - public function offsetSet($offset, $value): void + /** + * @param int|string $offset + * @param mixed $value + */ + public function offsetSet($offset, $value): void // @codingStandardsIgnoreLine { throw new BadMethodCallException(__METHOD__); } - public function offsetUnset($offset): void + /** @param int|string $offset */ + public function offsetUnset($offset): void // @codingStandardsIgnoreLine { throw new BadMethodCallException(__METHOD__); } diff --git a/src/PHPUnit/HttpMockTrait.php b/src/PHPUnit/HttpMockTrait.php index cd01edd..d4bd3b4 100644 --- a/src/PHPUnit/HttpMockTrait.php +++ b/src/PHPUnit/HttpMockTrait.php @@ -6,7 +6,7 @@ trigger_error(E_USER_DEPRECATED, sprintf('%s is deprecated. Use %s instead', HttpMockTrait::class, HttpMock::class)); -trait HttpMockTrait +trait HttpMockTrait // @codingStandardsIgnoreLine { use HttpMock; } diff --git a/src/Request/UnifiedRequest.php b/src/Request/UnifiedRequest.php index e5ec7e3..a8f01cf 100644 --- a/src/Request/UnifiedRequest.php +++ b/src/Request/UnifiedRequest.php @@ -7,8 +7,10 @@ use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Message\Header; use Guzzle\Http\Message\Header\HeaderCollection; +use Guzzle\Http\Message\PostFileInterface; use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\QueryString; +use Guzzle\Plugin\Cookie\Cookie; final class UnifiedRequest { @@ -61,7 +63,7 @@ public function getPostFields(): QueryString /** * Returns an associative array of POST field names to PostFileInterface objects * - * @return array + * @return array */ public function getPostFiles(): array { @@ -73,7 +75,7 @@ public function getPostFiles(): array * * @param string $fieldName POST fields to retrieve * - * @return array|null Returns an array wrapping an array of PostFileInterface objects + * @return array>|null Returns an array wrapping an array of PostFileInterface objects */ public function getPostFile(string $fieldName): ?array { @@ -114,7 +116,7 @@ public function getHeaders(): HeaderCollection /** * Get an array of message header lines * - * @return array + * @return array */ public function getHeaderLines(): array { @@ -240,7 +242,7 @@ public function getUrl(bool $asObject = false) /** * Get an array of Cookies * - * @return array + * @return array */ public function getCookies(): array { diff --git a/src/Server.php b/src/Server.php index fc0eaa9..3b30f69 100644 --- a/src/Server.php +++ b/src/Server.php @@ -46,7 +46,7 @@ public function start(callable $callback = null, array $env = []): void * @param int|float $timeout * @param int $signal */ - public function stop($timeout = 10, $signal = null): ?int + public function stop($timeout = 10, $signal = null): ?int // @codingStandardsIgnoreLine { return parent::stop($timeout, $signal); } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 38c7925..2307a10 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -32,6 +32,7 @@ public function tearDown(): void $this->tearDownHttpMock(); } + /** @return array */ public static function getPaths(): array { return [ diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 6745c32..1eb16c1 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -32,6 +32,7 @@ public function tearDown(): void $this->tearDownHttpMock(); } + /** @return array */ public static function getPaths(): array { return [ diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php index aa80bdc..6957540 100644 --- a/tests/Request/UnifiedRequestTest.php +++ b/tests/Request/UnifiedRequestTest.php @@ -32,6 +32,7 @@ public function setUp(): void $this->unifiedEnclosingEntityRequest = new UnifiedRequest($this->wrappedEntityEnclosingRequest); } + /** @return array,2:mixed}>> */ public static function provideMethods(): array { return [ @@ -58,6 +59,7 @@ public static function provideMethods(): array ]; } + /** @return array,2:mixed}>> */ public static function provideEntityEnclosingInterfaceMethods(): array { return [ @@ -69,8 +71,12 @@ public static function provideEntityEnclosingInterfaceMethods(): array ]; } - /** @dataProvider provideMethods */ - public function testMethodsFromRequestInterface($method, array $params = [], $returnValue = 'REQ'): void + /** + * @dataProvider provideMethods + * @param array $params + * @param mixed $returnValue + */ + public function testMethodsFromRequestInterface(string $method, array $params = [], $returnValue = 'REQ'): void { $this->wrappedRequest ->expects($this->once()) @@ -91,15 +97,19 @@ public function testMethodsFromRequestInterface($method, array $params = [], $re ); } - /** @dataProvider provideEntityEnclosingInterfaceMethods */ + /** + * @dataProvider provideEntityEnclosingInterfaceMethods + * @param array $params + * @param mixed $returnValue + */ public function testEntityEnclosingInterfaceMethods( - $method, + string $method, array $params = [], $returnValue = 'Return Value' ): void { $this->wrappedEntityEnclosingRequest - ->expects($this->once()) + ->expects(self::once()) ->method($method) ->willReturn($returnValue) ->with(...$params); @@ -110,11 +120,9 @@ public function testEntityEnclosingInterfaceMethods( ); $this->wrappedRequest - ->expects($this->any()) ->method('getMethod') ->willReturn('METHOD'); $this->wrappedRequest - ->expects($this->any()) ->method('getPath') ->willReturn('/foo'); diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index bd21c12..c5069fc 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -20,13 +20,14 @@ class RequestCollectionFacadeTest extends AbstractTestCase public function setUp(): void { - $this->client = $this->createMock('Guzzle\Http\ClientInterface'); + $this->client = $this->createMock(ClientInterface::class); $this->facade = new RequestCollectionFacade($this->client); $this->request = new Request('GET', '/_request/last'); $this->request->setClient($this->client); } - public static function provideMethodAndUrls(): array + /** @return array,3:string}> */ + public static function getMethodAndUrls(): array { return [ ['latest', '/_request/last'], @@ -38,7 +39,10 @@ public static function provideMethodAndUrls(): array ]; } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestingLatestRequest( string $method, string $path, @@ -55,7 +59,10 @@ public function testRequestingLatestRequest( self::assertSame('RECORDED=1', (string) $request->getBody()); } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestLatestResponseWithHttpAuth( string $method, string $path, @@ -77,7 +84,10 @@ public function testRequestLatestResponseWithHttpAuth( self::assertSame('CUSTOM UA', $request->getUserAgent()); } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestResponseWithInvalidStatusCode( string $method, string $path, @@ -93,7 +103,10 @@ public function testRequestResponseWithInvalidStatusCode( call_user_func_array([$this->facade, $method], $args); } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestResponseWithEmptyContentType( string $method, string $path, @@ -109,7 +122,10 @@ public function testRequestResponseWithEmptyContentType( call_user_func_array([$this->facade, $method], $args); } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestResponseWithInvalidContentType( string $method, string $path, @@ -125,7 +141,10 @@ public function testRequestResponseWithInvalidContentType( call_user_func_array([$this->facade, $method], $args); } - /** @dataProvider provideMethodAndUrls */ + /** + * @dataProvider getMethodAndUrls + * @param array $args + */ public function testRequestResponseWithDeserializationError( string $method, string $path, From 5b2514604a7288ed097707b8055c561f216173fa Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:16:37 +0200 Subject: [PATCH 06/38] CI --- .github/workflows/test.yaml | 4 ++++ composer.json | 3 ++- phpcs.xml.dist | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9b8a8c5..c7348b8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,3 +45,7 @@ jobs: - name: Run Tests run: composer tests continue-on-error: ${{ matrix.experimental }} + + - name: Check coding style + run: composer coding-style + continue-on-error: ${{ matrix.experimental }} diff --git a/composer.json b/composer.json index b330deb..0d59316 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "psr-4": {"InterNations\\Component\\HttpMock\\Tests\\": "tests/"} }, "scripts": { - "tests": "phpunit" + "tests": "phpunit", + "coding-style": "phpcs", } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 92c9d99..6c77b90 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -1,6 +1,8 @@ - + + ./src + ./tests From 99909aea12c66356c6f7a7e1c49b26c11aac55ce Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:18:54 +0200 Subject: [PATCH 07/38] Next --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0d59316..d26a81c 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,6 @@ }, "scripts": { "tests": "phpunit", - "coding-style": "phpcs", + "coding-style": "phpcs" } } From de52fa3bde9743176ed441ed13b18ace82760041 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:21:26 +0200 Subject: [PATCH 08/38] CI --- .github/workflows/test.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c7348b8..b20c40b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,11 +12,12 @@ jobs: fail-fast: false matrix: php-version: - - 7.1 - - 7.2 - - 7.3 - 7.4 + - 8.0 experimental: [false] + include: + - php-version: 8.1 + experimental: true continue-on-error: ${{ matrix.experimental }} steps: From dc87f315611e5bb83727a1947bf94e707aace0d1 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:22:28 +0200 Subject: [PATCH 09/38] PHP 8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d26a81c..706b938 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": "~7.4", + "php": "~7.4|~8.0", "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", From df2a529a122dc1009cd8fd44d9e4e048af7482c8 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 09:24:38 +0200 Subject: [PATCH 10/38] PHPUnit upgrade --- .gitignore | 1 + composer.json | 2 +- phpunit.xml.dist | 11 ++++++++--- tests/MockBuilderIntegrationTest.php | 2 +- tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php | 2 +- tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 7278a54..63ae91d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock state/*-* build/* phpunit.xml +.phpunit.result.cache diff --git a/composer.json b/composer.json index 706b938..afd9c72 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require-dev": { "internations/testing-component": "1.0.1", - "phpunit/phpunit": "^7" + "phpunit/phpunit": "^9" }, "autoload": { "psr-4": {"InterNations\\Component\\HttpMock\\": "src/"} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 51c72a8..8298e09 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,6 @@ + + + + + + ./tests/ @@ -17,8 +23,7 @@ - - + diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 9308438..259142a 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -89,7 +89,7 @@ public function testCreateExpectation(): void $this->assertSame('response body', (string) $client->post('/foo')->send()->getBody()); - $this->assertContains('CLOSURE MATCHER: POST /foo', $this->server->getErrorOutput()); + $this->assertTrue(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo') !== false); } public function testCreateTwoExpectationsAfterEachOther(): void diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 2307a10..9e1d90f 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -102,7 +102,7 @@ public function testErrorLogOutput(): void $this->tearDown(); $this->fail('Exception expected'); } catch (\Exception $e) { - $this->assertContains('HTTP mock server standard error output should be empty', $e->getMessage()); + $this->assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); } } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 1eb16c1..c3bec79 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -102,7 +102,7 @@ public function testErrorLogOutput(): void $this->tearDown(); $this->fail('Exception expected'); } catch (\Exception $e) { - $this->assertContains('HTTP mock server standard error output should be empty', $e->getMessage()); + $this->assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); } } From 0e9c41e7c5248ce5459c78ef805de33ab7e946d4 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 12:42:06 +0200 Subject: [PATCH 11/38] Next --- src/PHPUnit/HttpMockFacade.php | 1 + src/RequestStorage.php | 12 ++--- src/Server.php | 1 - src/app.php | 85 +++++++++++++++++----------------- 4 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index 46946e6..c484b4b 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -1,6 +1,7 @@ directory = $directory; } - /** @param mixed $data */ - public function store(Request $request, string $name, $data): void + /** @param array|array $data */ + public function store(Request $request, string $name, array $data): void { file_put_contents($this->getFileName($request, $name), serialize($data)); } - /** @return mixed */ - public function read(Request $request, string $name) + /** @return array|array */ + public function read(Request $request, string $name): array { $fileName = $this->getFileName($request, $name); @@ -33,7 +33,7 @@ public function read(Request $request, string $name) return Util::deserialize(file_get_contents($fileName)); } - /** @param mixed $data */ + /** @param Request|Expectation $data */ public function append(Request $request, string $name, $data): void { $list = $this->read($request, $name); @@ -41,7 +41,7 @@ public function append(Request $request, string $name, $data): void $this->store($request, $name, $list); } - /** @param mixed $data */ + /** @param Request|Expectation $data */ public function prepend(Request $request, string $name, $data): void { $list = $this->read($request, $name); diff --git a/src/Server.php b/src/Server.php index 3b30f69..82474d6 100644 --- a/src/Server.php +++ b/src/Server.php @@ -85,7 +85,6 @@ public function getConnectionString(): string */ public function setUp(array $expectations): void { - /** @var Expectation $expectation */ foreach ($expectations as $expectation) { $response = $this->getClient()->post( '/_expectation', diff --git a/src/app.php b/src/app.php index 032f3fb..49c1b53 100644 --- a/src/app.php +++ b/src/app.php @@ -1,4 +1,4 @@ -delete( '/_expectation', - static function (Request $request) use ($app) { - $app['storage']->clear($request, 'expectations'); + static function (Request $currentRequest) use ($app) { + $app['storage']->clear($currentRequest, 'expectations'); return new Response('', Response::HTTP_OK); } @@ -45,12 +44,12 @@ static function (Request $request) use ($app) { $app->post( '/_expectation', - static function (Request $request) use ($app) { + static function (Request $currentRequest) use ($app) { $matcher = []; - if ($request->request->has('matcher')) { - $matcherParameter = $request->request->get('matcher'); + if ($currentRequest->request->has('matcher')) { + $matcherParameter = $currentRequest->request->get('matcher'); if (!is_string($matcherParameter)) { return new Response( 'POST data key "matcher" must be a serialized list of closures', @@ -71,11 +70,11 @@ static function (Request $request) use ($app) { } } - if (!$request->request->has('response')) { + if (!$currentRequest->request->has('response')) { return new Response('POST data key "response" not found in POST data', Response::HTTP_EXPECTATION_FAILED); } - $response = Util::silentDeserialize($request->request->get('response')); + $response = Util::silentDeserialize($currentRequest->request->get('response')); if (!$response instanceof Response) { return new Response( @@ -86,8 +85,8 @@ static function (Request $request) use ($app) { $limiter = null; - if ($request->request->has('limiter')) { - $limiter = Util::silentDeserialize($request->request->get('limiter')); + if ($currentRequest->request->has('limiter')) { + $limiter = Util::silentDeserialize($currentRequest->request->get('limiter')); if (!is_callable($limiter)) { return new Response( @@ -101,7 +100,7 @@ static function (Request $request) use ($app) { $response->headers->set('X-Status-Code', $response->getStatusCode()); $app['storage']->prepend( - $request, + $currentRequest, 'expectations', ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0] ); @@ -111,31 +110,31 @@ static function (Request $request) use ($app) { ); $app->error( - static function (Exception $e, Request $request, $code, GetResponseForExceptionEvent $event = null) use ($app) { + static function (Exception $e, Request $currentRequest, int $code, GetResponseForExceptionEvent $event = null) use ($app) { if ($e instanceof NotFoundHttpException) { if (method_exists($event, 'allowCustomResponseCode')) { $event->allowCustomResponseCode(); } $app['storage']->append( - $request, + $currentRequest, 'requests', serialize( [ - 'server' => $request->server->all(), - 'request' => (string) $request, - 'enclosure' => $request->request->all(), + 'server' => $currentRequest->server->all(), + 'request' => (string) $currentRequest, + 'enclosure' => $currentRequest->request->all(), ] ) ); $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); - $expectations = $app['storage']->read($request, 'expectations'); + $expectations = $app['storage']->read($currentRequest, 'expectations'); foreach ($expectations as $pos => $expectation) { foreach ($expectation['matcher'] as $matcher) { - if (!$matcher($request)) { + if (!$matcher($currentRequest)) { continue 2; } } @@ -143,7 +142,7 @@ static function (Exception $e, Request $request, $code, GetResponseForExceptionE $applicable = !isset($expectation['limiter']) || $expectation['limiter']($expectation['runs']); ++$expectations[$pos]['runs']; - $app['storage']->store($request, 'expectations', $expectations); + $app['storage']->store($currentRequest, 'expectations', $expectations); if (!$applicable) { $notFoundResponse = new Response('Expectation not met', Response::HTTP_GONE); @@ -162,59 +161,59 @@ static function (Exception $e, Request $request, $code, GetResponseForExceptionE $app->get( '/_request/count', - static function (Request $request) use ($app) { - return count($app['storage']->read($request, 'requests')); + static function (Request $currentRequest) use ($app) { + return count($app['storage']->read($currentRequest, 'requests')); } ); $app->get( '/_request/{index}', - static function (Request $request, $index) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); + static function (Request $currentRequest, $index) use ($app) { + $requests = $app['storage']->read($currentRequest, 'requests'); - if (!isset($requestData[$index])) { + if (!isset($requests[$index])) { return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND); } - return new Response($requestData[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return new Response($requests[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); } )->assert('index', '\d+'); $app->delete( '/_request/{action}', - static function (Request $request, $action) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); + static function (Request $currentRequest, $action) use ($app) { + $requests = $app['storage']->read($currentRequest, 'requests'); $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); - $requestString = $fn($requestData); - $app['storage']->store($request, 'requests', $requestData); + $request = $fn($requests); + $app['storage']->store($currentRequest, 'requests', $requests); - if (!$requestString) { + if (!$request) { return new Response($action . ' not possible', Response::HTTP_NOT_FOUND); } - return new Response($requestString, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); } )->assert('index', '(last|first)'); $app->get( '/_request/{action}', - static function (Request $request, $action) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); + static function (Request $currentRequest, $action) use ($app) { + $requestData = $app['storage']->read($currentRequest, 'requests'); $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); - $requestString = $fn($requestData); + $request = $fn($requestData); - if (!$requestString) { + if (!$request) { return new Response($action . ' not available', Response::HTTP_NOT_FOUND); } - return new Response($requestString, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); } )->assert('index', '(last|first)'); $app->delete( '/_request', - static function (Request $request) use ($app) { - $app['storage']->store($request, 'requests', []); + static function (Request $currentRequest) use ($app) { + $app['storage']->store($currentRequest, 'requests', []); return new Response('', Response::HTTP_OK); } @@ -222,9 +221,9 @@ static function (Request $request) use ($app) { $app->delete( '/_all', - static function (Request $request) use ($app) { - $app['storage']->store($request, 'requests', []); - $app['storage']->store($request, 'expectations', []); + static function (Request $currentRequest) use ($app) { + $app['storage']->store($currentRequest, 'requests', []); + $app['storage']->store($currentRequest, 'expectations', []); return new Response('', Response::HTTP_OK); } From f537cf8291dc7046003484c39073dfff8ad1080d Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 12:44:27 +0200 Subject: [PATCH 12/38] Next --- .github/workflows/test.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b20c40b..111ed1f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: test: - name: PHP ${{ matrix.php-version }} (${{ matrix.experimental && 'experimental' || 'full support' }}) + name: PHP ${{ matrix.php-version }} (${{ matrix.experimental && 'experimental' || 'full support' }}, ${{ matrix.dependencies }} dependencies) runs-on: ubuntu-18.04 @@ -15,9 +15,11 @@ jobs: - 7.4 - 8.0 experimental: [false] + dependencies: [lowest, stable] include: - php-version: 8.1 experimental: true + dependencies: [lowest, stable] continue-on-error: ${{ matrix.experimental }} steps: @@ -34,7 +36,7 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v1 with: - composer-options: --prefer-dist + composer-options: --prefer-dist --prefer-${{ matrix.dependencies }} continue-on-error: ${{ matrix.experimental }} - name: Setup PCOV From 241adf46e312c3f5665a02f2a7f2f9add216aa4a Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 12:46:30 +0200 Subject: [PATCH 13/38] Next --- .github/workflows/test.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 111ed1f..1cec7e6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -19,7 +19,10 @@ jobs: include: - php-version: 8.1 experimental: true - dependencies: [lowest, stable] + dependencies: lowest + - php-version: 8.1 + experimental: true + dependencies: stable continue-on-error: ${{ matrix.experimental }} steps: @@ -36,7 +39,8 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v1 with: - composer-options: --prefer-dist --prefer-${{ matrix.dependencies }} + composer-options: --prefer-dist + dependency-versions: ${{ matrix.dependencies }} continue-on-error: ${{ matrix.experimental }} - name: Setup PCOV From 1a53f3ba53cf208550b5e50a9d331029fa3656a2 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 12:48:06 +0200 Subject: [PATCH 14/38] increase lower bound --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index afd9c72..8e7991d 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", - "jeremeamia/superclosure": "~2", + "jeremeamia/superclosure": "~2.1", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0" }, From 1bbbf62a1f988244251f4151d1adbdfc59584fbf Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 16:51:36 +0200 Subject: [PATCH 15/38] Symfony request instead of Guzzle request --- src/Request/SerializableRequest.php | 69 ++++++++++++++++ src/RequestCollectionFacade.php | 80 +++---------------- src/app.php | 17 ++-- tests/AppIntegrationTest.php | 52 ++++-------- tests/Fixtures/Request.php | 4 +- .../HttpMockMultiPHPUnitIntegrationTest.php | 18 ++--- ...HttpMockPHPUnitIntegrationBasePathTest.php | 2 +- .../HttpMockPHPUnitIntegrationTest.php | 18 ++--- tests/RequestCollectionFacadeTest.php | 42 ++++------ 9 files changed, 139 insertions(+), 163 deletions(-) create mode 100644 src/Request/SerializableRequest.php diff --git a/src/Request/SerializableRequest.php b/src/Request/SerializableRequest.php new file mode 100644 index 0000000..a817581 --- /dev/null +++ b/src/Request/SerializableRequest.php @@ -0,0 +1,69 @@ +getContent(); + return serialize([ + 'attributes' => $this->attributes, + 'request' => $this->request, + 'query' => $this->query, + 'server' => $this->server, + 'files' => $this->files, + 'cookies' => $this->cookies, + 'headers' => $this->headers, + 'content' => $this->content, + 'languages' => $this->languages, + 'charsets' => $this->charsets, + 'encodings' => $this->encodings, + 'acceptableContentTypes' => $this->acceptableContentTypes, + 'pathInfo' => $this->pathInfo, + 'requestUri' => $this->requestUri, + 'baseUrl' => $this->baseUrl, + 'basePath' => $this->basePath, + 'method' => $this->method, + 'format' => $this->format, + 'session' => $this->session, + 'locale' => $this->locale, + 'defaultLocale' => $this->defaultLocale, + ]); + } + + public function unserialize($data) + { + $attributes = unserialize($data); + + $this->attributes = $attributes['attributes']; + $this->request = $attributes['request']; + $this->query = $attributes['query']; + $this->server = $attributes['server']; + $this->files = $attributes['files']; + $this->cookies = $attributes['cookies']; + $this->headers = $attributes['headers']; + $this->content = $attributes['content']; + $this->languages = $attributes['languages']; + $this->charsets = $attributes['charsets']; + $this->encodings = $attributes['encodings']; + $this->acceptableContentTypes = $attributes['acceptableContentTypes']; + $this->pathInfo = $attributes['pathInfo']; + $this->requestUri = $attributes['requestUri']; + $this->baseUrl = $attributes['baseUrl']; + $this->basePath = $attributes['basePath']; + $this->method = $attributes['method']; + $this->format = $attributes['format']; + $this->session = $attributes['session']; + $this->locale = $attributes['locale']; + $this->defaultLocale = $attributes['defaultLocale']; + } +} diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index f233c5a..39eded3 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -3,11 +3,8 @@ use Countable; use Guzzle\Http\ClientInterface; -use Guzzle\Http\Message\EntityEnclosingRequestInterface; -use Guzzle\Http\Message\RequestFactory; -use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\Message\Response; -use InterNations\Component\HttpMock\Request\UnifiedRequest; +use Symfony\Component\HttpFoundation\Request; use UnexpectedValueException; class RequestCollectionFacade implements Countable @@ -19,44 +16,32 @@ public function __construct(ClientInterface $client) $this->client = $client; } - /** - */ - public function latest(): UnifiedRequest + public function latest(): Request { return $this->getRecordedRequest('/_request/last'); } - /** - */ - public function last(): UnifiedRequest + public function last(): Request { return $this->getRecordedRequest('/_request/last'); } - /** - */ - public function first(): UnifiedRequest + public function first(): Request { return $this->getRecordedRequest('/_request/first'); } - /** - */ - public function at(int $position): UnifiedRequest + public function at(int $position): Request { return $this->getRecordedRequest('/_request/' . $position); } - /** - */ - public function pop(): UnifiedRequest + public function pop(): Request { return $this->deleteRecordedRequest('/_request/last'); } - /** - */ - public function shift(): UnifiedRequest + public function shift(): Request { return $this->deleteRecordedRequest('/_request/first'); } @@ -73,10 +58,10 @@ public function count(): int /** * @throws UnexpectedValueException */ - private function parseRequestFromResponse(Response $response, string $path): UnifiedRequest + private function parseRequestFromResponse(Response $response, string $path): Request { try { - $requestInfo = Util::deserialize($response->getBody()); + return Util::deserialize($response->getBody()); } catch (UnexpectedValueException $e) { throw new UnexpectedValueException( sprintf('Cannot deserialize response from "%s": "%s"', $path, $response->getBody()), @@ -84,50 +69,9 @@ private function parseRequestFromResponse(Response $response, string $path): Uni $e ); } - - $request = RequestFactory::getInstance()->fromMessage($requestInfo['request']); - $params = $this->configureRequest( - $request, - $requestInfo['server'], - $requestInfo['enclosure'] ?? [] - ); - - return new UnifiedRequest($request, $params); - } - - /** - * @param array $server - * @param array $enclosure - * @return array - */ - private function configureRequest(RequestInterface $request, array $server, array $enclosure): array - { - if (isset($server['HTTP_HOST'])) { - $request->setHost($server['HTTP_HOST']); - } - - if (isset($server['HTTP_PORT'])) { - $request->setPort($server['HTTP_PORT']); - } - - if (isset($server['PHP_AUTH_USER'])) { - $request->setAuth($server['PHP_AUTH_USER'], $server['PHP_AUTH_PW'] ?? null); - } - - $params = []; - - if (isset($server['HTTP_USER_AGENT'])) { - $params['userAgent'] = $server['HTTP_USER_AGENT']; - } - - if ($request instanceof EntityEnclosingRequestInterface) { - $request->addPostFields($enclosure); - } - - return $params; } - private function getRecordedRequest(string $path): UnifiedRequest + private function getRecordedRequest(string $path): Request { $response = $this->client ->get($path) @@ -136,7 +80,7 @@ private function getRecordedRequest(string $path): UnifiedRequest return $this->parseResponse($response, $path); } - private function deleteRecordedRequest(string $path): UnifiedRequest + private function deleteRecordedRequest(string $path): Request { $response = $this->client ->delete($path) @@ -145,7 +89,7 @@ private function deleteRecordedRequest(string $path): UnifiedRequest return $this->parseResponse($response, $path); } - private function parseResponse(Response $response, string $path): UnifiedRequest + private function parseResponse(Response $response, string $path): Request { $statusCode = (int) $response->getStatusCode(); diff --git a/src/app.php b/src/app.php index 49c1b53..e201d7c 100644 --- a/src/app.php +++ b/src/app.php @@ -2,6 +2,7 @@ namespace InterNations\Component\HttpMock; use Exception; +use InterNations\Component\HttpMock\Request\SerializableRequest; use RuntimeException; use Silex\Application; use Symfony\Component\HttpFoundation\Request; @@ -30,6 +31,10 @@ ); } +Request::setFactory(function(...$args) { + return new SerializableRequest(...$args); +}); + $app = new Application(); $app['storage'] = new RequestStorage(getmypid(), __DIR__ . '/../state/'); @@ -116,17 +121,7 @@ static function (Exception $e, Request $currentRequest, int $code, GetResponseFo $event->allowCustomResponseCode(); } - $app['storage']->append( - $currentRequest, - 'requests', - serialize( - [ - 'server' => $currentRequest->server->all(), - 'request' => (string) $currentRequest, - 'enclosure' => $currentRequest->request->all(), - ] - ) - ); + $app['storage']->append($currentRequest, 'requests', serialize($currentRequest)); $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index 46eaa5a..8a7db42 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -4,6 +4,7 @@ use Closure; use Guzzle\Http\Message\RequestInterface; use InterNations\Component\HttpMock\Server; +use InterNations\Component\HttpMock\Util; use InterNations\Component\Testing\AbstractTestCase; use Guzzle\Http\Client; use Guzzle\Http\Message\RequestFactory; @@ -65,10 +66,10 @@ static function ($request) { $response = $this->client->get('/_request/latest')->send(); - /** @var EntityEnclosingRequest $request */ + /** @var Request $request */ $request = $this->parseRequestFromResponse($response); - $this->assertSame('1', (string) $request->getHeader('X-Special')); - $this->assertSame('post=data', (string) $request->getBody()); + $this->assertSame('1', (string) $request->headers->get('X-Special')); + $this->assertSame('post=data', $request->getContent()); } public function testRecording(): void @@ -87,41 +88,41 @@ public function testRecording(): void $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getRequestUri() ); $this->assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() ); $this->assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() ); $this->assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getRequestUri() ); $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getRequestUri() ); $this->assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode()); $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getPath() + $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getRequestUri() ); $this->assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getPath() + $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getRequestUri() ); $this->assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() ); $this->assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() ); $this->assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); } @@ -151,25 +152,6 @@ public function testErrorHandling(): void $this->assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } - public function testServerParamsAreRecorded(): void - { - $this->client - ->setUserAgent('CUSTOM UA') - ->get('/foo') - ->setAuth('username', 'password') - ->setProtocolVersion('1.0') - ->send(); - - $latestRequest = unserialize($this->client->get('/_request/latest')->send()->getBody()); - - $this->assertSame(HTTP_MOCK_HOST, $latestRequest['server']['SERVER_NAME']); - $this->assertSame(HTTP_MOCK_PORT, $latestRequest['server']['SERVER_PORT']); - $this->assertSame('username', $latestRequest['server']['PHP_AUTH_USER']); - $this->assertSame('password', $latestRequest['server']['PHP_AUTH_PW']); - $this->assertSame('HTTP/1.0', $latestRequest['server']['SERVER_PROTOCOL']); - $this->assertSame('CUSTOM UA', $latestRequest['server']['HTTP_USER_AGENT']); - } - public function testNewestExpectationsAreFirstEvaluated(): void { $this->client->post( @@ -219,11 +201,9 @@ public function testServerLogsAreNotInErrorOutput(): void self::$server1->clearErrorOutput(); } - private function parseRequestFromResponse(GuzzleResponse $response): RequestInterface + private function parseRequestFromResponse(GuzzleResponse $response): Request { - $body = unserialize($response->getBody()); - - return RequestFactory::getInstance()->fromMessage($body['request']); + return Util::deserialize($response->getBody()); } /** @@ -237,7 +217,7 @@ private function createExpectationParams(array $closures, Response $response): a } return [ - 'matcher' => serialize($closures), + 'matcher' => serialize($closures), 'response' => serialize($response), ]; } diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index 6be38fe..0356251 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -1,9 +1,9 @@ http['firstNamedServer']->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->last(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->first(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->at(0); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->pop(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); $request = $this->http['firstNamedServer']->requests->shift(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $this->expectException('UnexpectedValueException'); @@ -201,7 +201,7 @@ public function testComplexResponse(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); + $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } public function testPutRequest(): void @@ -220,7 +220,7 @@ public function testPutRequest(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->getPostField('put-key')); + $this->assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->request->get('put-key')); } public function testPostRequest(): void @@ -239,7 +239,7 @@ public function testPostRequest(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); + $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } public function testFatalError(): void diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index b8c3f2e..58fb66b 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -43,6 +43,6 @@ public function testSimpleRequest(): void $request = $this->http->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame('/custom-base-path/foo', $request->getPath()); + $this->assertSame('/custom-base-path/foo', $request->getRequestUri()); } } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index c3bec79..db177d5 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -56,29 +56,29 @@ public function testSimpleRequest(string $path): void $request = $this->http->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http->requests->last(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http->requests->first(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http->requests->at(0); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $request = $this->http->requests->pop(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); $request = $this->http->requests->shift(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getRequestUri()); $this->expectException('UnexpectedValueException'); @@ -201,7 +201,7 @@ public function testComplexResponse(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); + $this->assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } public function testPutRequest(): void @@ -220,7 +220,7 @@ public function testPutRequest(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http->requests->latest()->getPostField('put-key')); + $this->assertSame('put-value', $this->http->requests->latest()->request->get('put-key')); } public function testPostRequest(): void @@ -239,7 +239,7 @@ public function testPostRequest(): void $this->assertSame('BODY', $response->getBody(true)); $this->assertSame(201, $response->getStatusCode()); $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); + $this->assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } public function testCountRequests(): void diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index c5069fc..4a39704 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -55,8 +55,8 @@ public function testRequestingLatestRequest( $request = call_user_func_array([$this->facade, $method], $args); self::assertSame('POST', $request->getMethod()); - self::assertSame('/foo', $request->getPath()); - self::assertSame('RECORDED=1', (string) $request->getBody()); + self::assertSame('/foo', $request->getRequestUri()); + self::assertSame('RECORDED=1', $request->getContent()); } /** @@ -72,16 +72,17 @@ public function testRequestLatestResponseWithHttpAuth( { $this->mockClient($path, $this->createComplexResponse(), $httpMethod); + /** @var \Symfony\Component\HttpFoundation\Request $request */ $request = call_user_func_array([$this->facade, $method], $args); self::assertSame('POST', $request->getMethod()); - self::assertSame('/foo', $request->getPath()); - self::assertSame('RECORDED=1', (string) $request->getBody()); + self::assertSame('/foo', $request->getRequestUri()); + self::assertSame('RECORDED=1', $request->getContent()); self::assertSame('host', $request->getHost()); self::assertSame(1234, $request->getPort()); - self::assertSame('username', $request->getUsername()); + self::assertSame('username', $request->getUser()); self::assertSame('password', $request->getPassword()); - self::assertSame('CUSTOM UA', $request->getUserAgent()); + self::assertSame('CUSTOM UA', $request->headers->get('User-Agent')); } /** @@ -185,12 +186,7 @@ private function createSimpleResponse(): Response return new Response( '200', ['Content-Type' => 'text/plain'], - serialize( - [ - 'server' => [], - 'request' => (string) $recordedRequest, - ] - ) + serialize($recordedRequest) ); } @@ -200,25 +196,17 @@ private function createComplexResponse(): Response $recordedRequest->setMethod('POST'); $recordedRequest->setRequestUri('/foo'); $recordedRequest->setContent('RECORDED=1'); - $recordedRequest->headers->set('Php-Auth-User', 'ignored'); - $recordedRequest->headers->set('Php-Auth-Pw', 'ignored'); - $recordedRequest->headers->set('User-Agent', 'ignored'); + $recordedRequest->server->set('SERVER_NAME', 'host'); + $recordedRequest->server->set('SERVER_PORT', 1234); + $recordedRequest->headers->set('Php-Auth-User', 'username'); + $recordedRequest->headers->set('Php-Auth-Pw', 'password'); + $recordedRequest->headers->set('User-Agent', 'CUSTOM UA'); + return new Response( '200', ['Content-Type' => 'text/plain; charset=UTF-8'], - serialize( - [ - 'server' => [ - 'HTTP_HOST' => 'host', - 'HTTP_PORT' => 1234, - 'PHP_AUTH_USER' => 'username', - 'PHP_AUTH_PW' => 'password', - 'HTTP_USER_AGENT' => 'CUSTOM UA', - ], - 'request' => (string) $recordedRequest, - ] - ) + serialize($recordedRequest) ); } From 020cd2eb63151e1bf84cc5512e44d9c9630f3950 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 16:55:32 +0200 Subject: [PATCH 16/38] Cleanup --- src/Request/SerializableRequest.php | 9 ++------- src/app.php | 4 +--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Request/SerializableRequest.php b/src/Request/SerializableRequest.php index a817581..42c0f96 100644 --- a/src/Request/SerializableRequest.php +++ b/src/Request/SerializableRequest.php @@ -1,14 +1,8 @@ $data */ + public function unserialize($data): void // @codingStandardsIgnoreLine { $attributes = unserialize($data); diff --git a/src/app.php b/src/app.php index e201d7c..dee8af9 100644 --- a/src/app.php +++ b/src/app.php @@ -31,9 +31,7 @@ ); } -Request::setFactory(function(...$args) { - return new SerializableRequest(...$args); -}); +Request::setFactory(static fn (...$args) => new SerializableRequest(...$args)); $app = new Application(); $app['storage'] = new RequestStorage(getmypid(), __DIR__ . '/../state/'); From 538efd34c1ac6761bb160c99d837ff1e404a733f Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:10:31 +0200 Subject: [PATCH 17/38] increase lower bound --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8e7991d..713e66b 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", - "jeremeamia/superclosure": "~2.1", + "jeremeamia/superclosure": "~2.2", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0" }, From fd639363dfaa5e4b3a41b381cac01f03711494ff Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:12:20 +0200 Subject: [PATCH 18/38] increase lower bound --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 713e66b..b5503fd 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", - "jeremeamia/superclosure": "~2.2", + "jeremeamia/superclosure": "~2.3", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0" }, From 3f251e18a61413961e0653c3023d517f3e98499c Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:14:30 +0200 Subject: [PATCH 19/38] increase lower bound --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b5503fd..c288a8b 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", - "jeremeamia/superclosure": "~2.3", + "jeremeamia/superclosure": "~2.4", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0" }, From 6d29e2181c98f024495a30f6aabb43d1d20f510e Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:30:21 +0200 Subject: [PATCH 20/38] Different closure library --- composer.json | 4 ++-- src/Expectation.php | 2 +- src/Matcher/ExtractorBasedMatcher.php | 2 +- src/Matcher/Matcher.php | 2 +- src/ResponseBuilder.php | 2 +- tests/AppIntegrationTest.php | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index c288a8b..70ed472 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ "silex/silex": "~2.0", "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", - "jeremeamia/superclosure": "~2.4", "lstrojny/hmmmath": ">=0.5.0", - "slevomat/coding-standard": "^7.0" + "slevomat/coding-standard": "^7.0", + "opis/closure": "^3.6" }, "require-dev": { "internations/testing-component": "1.0.1", diff --git a/src/Expectation.php b/src/Expectation.php index abc4c3a..fead5d4 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -4,8 +4,8 @@ use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\Matcher\Matcher; -use SuperClosure\SerializableClosure; use Closure; +use Opis\Closure\SerializableClosure; use Symfony\Component\HttpFoundation\Response; class Expectation diff --git a/src/Matcher/ExtractorBasedMatcher.php b/src/Matcher/ExtractorBasedMatcher.php index 82c0822..4aa16cc 100644 --- a/src/Matcher/ExtractorBasedMatcher.php +++ b/src/Matcher/ExtractorBasedMatcher.php @@ -2,7 +2,7 @@ namespace InterNations\Component\HttpMock\Matcher; use Closure; -use SuperClosure\SerializableClosure; +use Opis\Closure\SerializableClosure; use Symfony\Component\HttpFoundation\Request; abstract class ExtractorBasedMatcher implements Matcher diff --git a/src/Matcher/Matcher.php b/src/Matcher/Matcher.php index 2c88478..ae9c8cf 100644 --- a/src/Matcher/Matcher.php +++ b/src/Matcher/Matcher.php @@ -1,8 +1,8 @@ Date: Tue, 11 May 2021 17:34:43 +0200 Subject: [PATCH 21/38] Next --- doc/start.md | 8 +- tests/AppIntegrationTest.php | 68 +++++------ tests/Matcher/ExtractorFactoryTest.php | 38 +++--- tests/MockBuilderIntegrationTest.php | 50 ++++---- .../HttpMockMultiPHPUnitIntegrationTest.php | 86 +++++++------- ...HttpMockPHPUnitIntegrationBasePathTest.php | 6 +- .../HttpMockPHPUnitIntegrationTest.php | 110 +++++++++--------- tests/Request/UnifiedRequestTest.php | 14 +-- 8 files changed, 190 insertions(+), 190 deletions(-) diff --git a/doc/start.md b/doc/start.md index 83fa653..39b34d3 100644 --- a/doc/start.md +++ b/doc/start.md @@ -45,7 +45,7 @@ class ExampleTest extends TestCase ->end(); $this->http->setUp(); - $this->assertSame('mocked body', file_get_contents('http://localhost:8082/foo')); + self::assertSame('mocked body', file_get_contents('http://localhost:8082/foo')); } public function testAccessingRecordedRequests(): void @@ -59,10 +59,10 @@ class ExampleTest extends TestCase ->end(); $this->http->setUp(); - $this->assertSame('mocked body', $this->http->client->post('http://localhost:8082/foo')->send()->getBody(true)); + self::assertSame('mocked body', $this->http->client->post('http://localhost:8082/foo')->send()->getBody(true)); - $this->assertSame('POST', $this->http->requests->latest()->getMethod()); - $this->assertSame('/foo', $this->http->requests->latest()->getPath()); + self::assertSame('POST', $this->http->requests->latest()->getMethod()); + self::assertSame('/foo', $this->http->requests->latest()->getPath()); } } ``` diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index b274534..ef673eb 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -56,75 +56,75 @@ static function ($request) { new Response('fake body', 200) ) )->send(); - $this->assertSame('', (string) $response->getBody()); - $this->assertSame(201, $response->getStatusCode()); + self::assertSame('', (string) $response->getBody()); + self::assertSame(201, $response->getStatusCode()); $response = $this->client->post('/foobar', ['X-Special' => 1], ['post' => 'data'])->send(); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('fake body', (string) $response->getBody()); + self::assertSame(200, $response->getStatusCode()); + self::assertSame('fake body', (string) $response->getBody()); $response = $this->client->get('/_request/latest')->send(); /** @var Request $request */ $request = $this->parseRequestFromResponse($response); - $this->assertSame('1', (string) $request->headers->get('X-Special')); - $this->assertSame('post=data', $request->getContent()); + self::assertSame('1', (string) $request->headers->get('X-Special')); + self::assertSame('post=data', $request->getContent()); } public function testRecording(): void { $this->client->delete('/_all')->send(); - $this->assertSame(404, $this->client->get('/_request/latest')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/0')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/first')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/last')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/latest')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/0')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/first')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/last')->send()->getStatusCode()); $this->client->get('/req/0')->send(); $this->client->get('/req/1')->send(); $this->client->get('/req/2')->send(); $this->client->get('/req/3')->send(); - $this->assertSame( + self::assertSame( '/req/3', $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/0', $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/1', $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/2', $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/3', $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getRequestUri() ); - $this->assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode()); - $this->assertSame( + self::assertSame( '/req/3', $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/0', $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/1', $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() ); - $this->assertSame( + self::assertSame( '/req/2', $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() ); - $this->assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); } public function testErrorHandling(): void @@ -132,24 +132,24 @@ public function testErrorHandling(): void $this->client->delete('/_all')->send(); $response = $this->client->post('/_expectation', null, ['matcher' => ''])->send(); - $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); + self::assertSame(417, $response->getStatusCode()); + self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); $response = $this->client->post('/_expectation', null, ['matcher' => ['foo']])->send(); - $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); + self::assertSame(417, $response->getStatusCode()); + self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); $response = $this->client->post('/_expectation', null, [])->send(); - $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "response" not found in POST data', (string) $response->getBody()); + self::assertSame(417, $response->getStatusCode()); + self::assertSame('POST data key "response" not found in POST data', (string) $response->getBody()); $response = $this->client->post('/_expectation', null, ['response' => ''])->send(); - $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "response" must be a serialized Symfony response', (string) $response->getBody()); + self::assertSame(417, $response->getStatusCode()); + self::assertSame('POST data key "response" must be a serialized Symfony response', (string) $response->getBody()); $response = $this->client->post('/_expectation', null, ['response' => serialize(new Response()), 'limiter' => 'foo'])->send(); - $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); + self::assertSame(417, $response->getStatusCode()); + self::assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } public function testNewestExpectationsAreFirstEvaluated(): void @@ -166,7 +166,7 @@ static function ($request) { new Response('first', 200) ) )->send(); - $this->assertSame('first', $this->client->get('/')->send()->getBody(true)); + self::assertSame('first', $this->client->get('/')->send()->getBody(true)); $this->client->post( '/_expectation', @@ -180,7 +180,7 @@ static function ($request) { new Response('second', 200) ) )->send(); - $this->assertSame('second', $this->client->get('/')->send()->getBody(true)); + self::assertSame('second', $this->client->get('/')->send()->getBody(true)); } public function testServerLogsAreNotInErrorOutput(): void @@ -196,7 +196,7 @@ public function testServerLogsAreNotInErrorOutput(): void $actualServerErrorOutput = self::$server1->getErrorOutput(); - $this->assertEquals($expectedServerErrorOutput, $actualServerErrorOutput); + self::assertEquals($expectedServerErrorOutput, $actualServerErrorOutput); self::$server1->clearErrorOutput(); } diff --git a/tests/Matcher/ExtractorFactoryTest.php b/tests/Matcher/ExtractorFactoryTest.php index ceaa323..dcd4bc0 100644 --- a/tests/Matcher/ExtractorFactoryTest.php +++ b/tests/Matcher/ExtractorFactoryTest.php @@ -21,62 +21,62 @@ public function setUp(): void public function testGetMethod(): void { $this->request - ->expects($this->once()) + ->expects(self::once()) ->method('getMethod') - ->will($this->returnValue('POST')); + ->willReturn('POST'); $extractor = $this->extractorFactory->createMethodExtractor(); - $this->assertSame('POST', $extractor($this->request)); + self::assertSame('POST', $extractor($this->request)); } public function testGetPath(): void { $this->request - ->expects($this->once()) + ->expects(self::once()) ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + ->willReturn('/foo/bar'); $extractor = $this->extractorFactory->createPathExtractor(); - $this->assertSame('/foo/bar', $extractor($this->request)); + self::assertSame('/foo/bar', $extractor($this->request)); } public function testGetPathWithBasePath(): void { $this->request - ->expects($this->once()) + ->expects(self::once()) ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + ->willReturn('/foo/bar'); $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('/bar', $extractor($this->request)); + self::assertSame('/bar', $extractor($this->request)); } public function testGetPathWithBasePathTrailingSlash(): void { $this->request - ->expects($this->once()) + ->expects(self::once()) ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + ->willReturn('/foo/bar'); $extractorFactory = new ExtractorFactory('/foo/'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('/bar', $extractor($this->request)); + self::assertSame('/bar', $extractor($this->request)); } public function testGetPathWithBasePathThatDoesNotMatch(): void { $this->request - ->expects($this->once()) + ->expects(self::once()) ->method('getPathInfo') - ->will($this->returnValue('/bar')); + ->willReturn('/bar'); $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('', $extractor($this->request)); + self::assertSame('', $extractor($this->request)); } public function testGetHeaderWithExistingHeader(): void @@ -93,7 +93,7 @@ public function testGetHeaderWithExistingHeader(): void $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createHeaderExtractor('content-type'); - $this->assertSame('application/json', $extractor($request)); + self::assertSame('application/json', $extractor($request)); } public function testGetHeaderWithNonExistingHeader(): void @@ -110,7 +110,7 @@ public function testGetHeaderWithNonExistingHeader(): void $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createHeaderExtractor('content-type'); - $this->assertNull($extractor($request)); + self::assertNull($extractor($request)); } public function testHeaderExistsWithExistingHeader(): void @@ -127,7 +127,7 @@ public function testHeaderExistsWithExistingHeader(): void $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createHeaderExistsExtractor('content-type'); - $this->assertTrue($extractor($request)); + self::assertTrue($extractor($request)); } public function testHeaderExistsWithNonExistingHeader(): void @@ -144,6 +144,6 @@ public function testHeaderExistsWithNonExistingHeader(): void $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createHeaderExistsExtractor('content-type'); - $this->assertFalse($extractor($request)); + self::assertFalse($extractor($request)); } } diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 259142a..31002b3 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -53,11 +53,11 @@ public function testCreateExpectation(): void ->header('X-Foo', 'Bar') ->end(); - $this->assertSame($this->builder, $builder); + self::assertSame($this->builder, $builder); $expectations = $this->builder->flushExpectations(); - $this->assertCount(1, $expectations); + self::assertCount(1, $expectations); /** @var Expectation $expectation */ $expectation = current($expectations); @@ -68,28 +68,28 @@ public function testCreateExpectation(): void $run = 0; $oldValue = ini_set('error_log', '/dev/null'); foreach ($expectation->getMatcherClosures() as $closure) { - $this->assertTrue($closure($request)); + self::assertTrue($closure($request)); $unserializedClosure = unserialize(serialize($closure)); - $this->assertTrue($unserializedClosure($request)); + self::assertTrue($unserializedClosure($request)); $run++; } ini_set('error_log', $oldValue); - $this->assertSame(3, $run); + self::assertSame(3, $run); $expectation->getResponse()->setDate(new DateTime('2012-11-10 09:08:07', new DateTimeZone('UTC'))); $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cache, private\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; - $this->assertSame($response, (string)$expectation->getResponse()); + self::assertSame($response, (string)$expectation->getResponse()); $this->server->setUp($expectations); $client = $this->server->getClient(); - $this->assertSame('response body', (string) $client->post('/foo')->send()->getBody()); + self::assertSame('response body', (string) $client->post('/foo')->send()->getBody()); - $this->assertTrue(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo') !== false); + self::assertTrue(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo') !== false); } public function testCreateTwoExpectationsAfterEachOther(): void @@ -114,10 +114,10 @@ public function testCreateTwoExpectationsAfterEachOther(): void ->end(); $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); - $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); + self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); + self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); + self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); + self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); } public function testCreateSuccessiveExpectationsOnSameWhen(): void @@ -146,9 +146,9 @@ public function testCreateSuccessiveExpectationsOnSameWhen(): void $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('called once', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('called twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('called once', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('called twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } public function testCreateSuccessiveExpectationsWithAny(): void @@ -177,9 +177,9 @@ public function testCreateSuccessiveExpectationsWithAny(): void $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('any', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('any', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void @@ -201,8 +201,8 @@ public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } public function testCreateSuccessiveExpectationsWithOnce(): void @@ -231,10 +231,10 @@ public function testCreateSuccessiveExpectationsWithOnce(): void $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - $this->assertSame('Expectation not met', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('Expectation not met', (string) $this->server->getClient()->post('/resource')->send()->getBody()); } } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 9935290..4d8bf67 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -52,33 +52,33 @@ public function testSimpleRequest(string $path): void ->end(); $this->http['firstNamedServer']->setUp(); - $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); $request = $this->http['firstNamedServer']->requests->latest(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->last(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->first(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->at(0); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http['firstNamedServer']->requests->pop(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); - $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); $request = $this->http['firstNamedServer']->requests->shift(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $this->expectException('UnexpectedValueException'); @@ -100,17 +100,17 @@ public function testErrorLogOutput(): void // Should fail during tear down as we have an error_log() on the server side try { $this->tearDown(); - $this->fail('Exception expected'); + self::fail('Exception expected'); } catch (\Exception $e) { - $this->assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); + self::assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); } } public function testFailedRequest(): void { $response = $this->http['firstNamedServer']->client->get('/foo')->send(); - $this->assertSame(404, $response->getStatusCode()); - $this->assertSame('No matching expectation found', (string) $response->getBody()); + self::assertSame(404, $response->getStatusCode()); + self::assertSame('No matching expectation found', (string) $response->getBody()); } public function testStopServer(): void @@ -122,7 +122,7 @@ public function testStopServer(): void public function testHttpServerIsRestartedIfATestStopsIt(): void { $response = $this->http['firstNamedServer']->client->get('/')->send(); - $this->assertSame(404, $response->getStatusCode()); + self::assertSame(404, $response->getStatusCode()); } public function testLimitDurationOfAResponse(): void @@ -136,10 +136,10 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http['firstNamedServer']->setUp(); $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(410, $secondResponse->getStatusCode()); - $this->assertSame('Expectation not met', $secondResponse->getBody(true)); + self::assertSame(410, $secondResponse->getStatusCode()); + self::assertSame('Expectation not met', $secondResponse->getBody(true)); $this->http['firstNamedServer']->mock ->exactly(2) @@ -150,12 +150,12 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http['firstNamedServer']->setUp(); $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $secondResponse->getStatusCode()); + self::assertSame(200, $secondResponse->getStatusCode()); $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(410, $thirdResponse->getStatusCode()); - $this->assertSame('Expectation not met', $thirdResponse->getBody(true)); + self::assertSame(410, $thirdResponse->getStatusCode()); + self::assertSame('Expectation not met', $thirdResponse->getBody(true)); $this->http['firstNamedServer']->mock ->any() @@ -166,11 +166,11 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http['firstNamedServer']->setUp(); $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $secondResponse->getStatusCode()); + self::assertSame(200, $secondResponse->getStatusCode()); $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); - $this->assertSame(200, $thirdResponse->getStatusCode()); + self::assertSame(200, $thirdResponse->getStatusCode()); } public function testCallbackOnResponse(): void @@ -182,7 +182,7 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http['firstNamedServer']->setUp(); - $this->assertSame('CALLBACK', $this->http['firstNamedServer']->client->post('/')->send()->getBody(true)); + self::assertSame('CALLBACK', $this->http['firstNamedServer']->client->post('/')->send()->getBody(true)); } public function testComplexResponse(): void @@ -198,10 +198,10 @@ public function testComplexResponse(): void $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } public function testPutRequest(): void @@ -217,10 +217,10 @@ public function testPutRequest(): void $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->request->get('put-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->request->get('put-key')); } public function testPostRequest(): void @@ -236,16 +236,16 @@ public function testPostRequest(): void $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } public function testFatalError(): void { if (version_compare(PHP_VERSION, '7.0', '<')) { - $this->markTestSkipped('Comment in to test if fatal errors are properly handled'); + self::markTestSkipped('Comment in to test if fatal errors are properly handled'); } $this->expectException('Error'); diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index 58fb66b..f3ca0ef 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -39,10 +39,10 @@ public function testSimpleRequest(): void ->end(); $this->http->setUp(); - $this->assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->send()->getBody()); + self::assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->send()->getBody()); $request = $this->http->requests->latest(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame('/custom-base-path/foo', $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame('/custom-base-path/foo', $request->getRequestUri()); } } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index db177d5..472b0b9 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -52,33 +52,33 @@ public function testSimpleRequest(string $path): void ->end(); $this->http->setUp(); - $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); $request = $this->http->requests->latest(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http->requests->last(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http->requests->first(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http->requests->at(0); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $request = $this->http->requests->pop(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); - $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); $request = $this->http->requests->shift(); - $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getRequestUri()); + self::assertSame('GET', $request->getMethod()); + self::assertSame($path, $request->getRequestUri()); $this->expectException('UnexpectedValueException'); @@ -100,17 +100,17 @@ public function testErrorLogOutput(): void // Should fail during tear down as we have an error_log() on the server side try { $this->tearDown(); - $this->fail('Exception expected'); + self::fail('Exception expected'); } catch (\Exception $e) { - $this->assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); + self::assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); } } public function testFailedRequest(): void { $response = $this->http->client->get('/foo')->send(); - $this->assertSame(404, $response->getStatusCode()); - $this->assertSame('No matching expectation found', (string) $response->getBody()); + self::assertSame(404, $response->getStatusCode()); + self::assertSame('No matching expectation found', (string) $response->getBody()); } public function testStopServer(): void @@ -122,7 +122,7 @@ public function testStopServer(): void public function testHttpServerIsRestartedIfATestStopsIt(): void { $response = $this->http->client->get('/')->send(); - $this->assertSame(404, $response->getStatusCode()); + self::assertSame(404, $response->getStatusCode()); } public function testLimitDurationOfAResponse(): void @@ -136,10 +136,10 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http->setUp(); $firstResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http->client->post('/')->send(); - $this->assertSame(410, $secondResponse->getStatusCode()); - $this->assertSame('Expectation not met', $secondResponse->getBody(true)); + self::assertSame(410, $secondResponse->getStatusCode()); + self::assertSame('Expectation not met', $secondResponse->getBody(true)); $this->http->mock ->exactly(2) @@ -150,12 +150,12 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http->setUp(); $firstResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $secondResponse->getStatusCode()); + self::assertSame(200, $secondResponse->getStatusCode()); $thirdResponse = $this->http->client->post('/')->send(); - $this->assertSame(410, $thirdResponse->getStatusCode()); - $this->assertSame('Expectation not met', $thirdResponse->getBody(true)); + self::assertSame(410, $thirdResponse->getStatusCode()); + self::assertSame('Expectation not met', $thirdResponse->getBody(true)); $this->http->mock ->any() @@ -166,11 +166,11 @@ public function testLimitDurationOfAResponse(): void ->end(); $this->http->setUp(); $firstResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $firstResponse->getStatusCode()); + self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $secondResponse->getStatusCode()); + self::assertSame(200, $secondResponse->getStatusCode()); $thirdResponse = $this->http->client->post('/')->send(); - $this->assertSame(200, $thirdResponse->getStatusCode()); + self::assertSame(200, $thirdResponse->getStatusCode()); } public function testCallbackOnResponse(): void @@ -182,7 +182,7 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http->setUp(); - $this->assertSame('CALLBACK', $this->http->client->post('/')->send()->getBody(true)); + self::assertSame('CALLBACK', $this->http->client->post('/')->send()->getBody(true)); } public function testComplexResponse(): void @@ -198,10 +198,10 @@ public function testComplexResponse(): void $this->http->setUp(); $response = $this->http->client ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } public function testPutRequest(): void @@ -217,10 +217,10 @@ public function testPutRequest(): void $this->http->setUp(); $response = $this->http->client ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http->requests->latest()->request->get('put-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('put-value', $this->http->requests->latest()->request->get('put-key')); } public function testPostRequest(): void @@ -236,10 +236,10 @@ public function testPostRequest(): void $this->http->setUp(); $response = $this->http->client ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); - $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); + self::assertSame('BODY', $response->getBody(true)); + self::assertSame(201, $response->getStatusCode()); + self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } public function testCountRequests(): void @@ -252,9 +252,9 @@ public function testCountRequests(): void ->end(); $this->http->setUp(); - $this->assertCount(0, $this->http->requests); - $this->assertSame('resource body', (string) $this->http->client->get('/resource')->send()->getBody()); - $this->assertCount(1, $this->http->requests); + self::assertCount(0, $this->http->requests); + self::assertSame('resource body', (string) $this->http->client->get('/resource')->send()->getBody()); + self::assertCount(1, $this->http->requests); } public function testMatchQueryString(): void @@ -272,10 +272,10 @@ static function (Request $request) { ->end(); $this->http->setUp(); - $this->assertSame('query string', (string) $this->http->client->get('/?key1=')->send()->getBody()); + self::assertSame('query string', (string) $this->http->client->get('/?key1=')->send()->getBody()); - $this->assertSame(Response::HTTP_NOT_FOUND, $this->http->client->get('/')->send()->getStatusCode()); - $this->assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->send()->getStatusCode()); + self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->get('/')->send()->getStatusCode()); + self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->send()->getStatusCode()); } public function testMatchRegex(): void @@ -288,8 +288,8 @@ public function testMatchRegex(): void ->end(); $this->http->setUp(); - $this->assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); - $this->assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); + self::assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); + self::assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); } public function testMatchQueryParams(): void @@ -307,19 +307,19 @@ public function testMatchQueryParams(): void ->end(); $this->http->setUp(); - $this->assertSame( + self::assertSame( 'response', (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->send()->getBody() ); - $this->assertSame( + self::assertSame( Response::HTTP_NOT_FOUND, $this->http->client->get('/?p1=&p2=v2&p3=foo')->send()->getStatusCode() ); - $this->assertSame( + self::assertSame( Response::HTTP_NOT_FOUND, $this->http->client->get('/?p1=')->send()->getStatusCode() ); - $this->assertSame( + self::assertSame( Response::HTTP_NOT_FOUND, $this->http->client->get('/?p3=foo')->send()->getStatusCode() ); @@ -328,7 +328,7 @@ public function testMatchQueryParams(): void public function testFatalError(): void { if (version_compare(PHP_VERSION, '7.0', '<')) { - $this->markTestSkipped('Comment in to test if fatal errors are properly handled'); + self::markTestSkipped('Comment in to test if fatal errors are properly handled'); } $this->expectException('Error'); diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php index 6957540..89992c7 100644 --- a/tests/Request/UnifiedRequestTest.php +++ b/tests/Request/UnifiedRequestTest.php @@ -79,19 +79,19 @@ public static function provideEntityEnclosingInterfaceMethods(): array public function testMethodsFromRequestInterface(string $method, array $params = [], $returnValue = 'REQ'): void { $this->wrappedRequest - ->expects($this->once()) + ->expects(self::once()) ->method($method) ->willReturn($returnValue) ->with(...$params); - $this->assertSame($returnValue, call_user_func_array([$this->unifiedRequest, $method], $params)); + self::assertSame($returnValue, call_user_func_array([$this->unifiedRequest, $method], $params)); $this->wrappedEntityEnclosingRequest - ->expects($this->once()) + ->expects(self::once()) ->method($method) ->willReturn($returnValue) ->with(...$params); - $this->assertSame( + self::assertSame( $returnValue, call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) ); @@ -114,7 +114,7 @@ public function testEntityEnclosingInterfaceMethods( ->willReturn($returnValue) ->with(...$params); - $this->assertSame( + self::assertSame( $returnValue, call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) ); @@ -141,9 +141,9 @@ public function testEntityEnclosingInterfaceMethods( public function testUserAgent(): void { - $this->assertNull($this->unifiedRequest->getUserAgent()); + self::assertNull($this->unifiedRequest->getUserAgent()); $unifiedRequest = new UnifiedRequest($this->wrappedRequest, ['userAgent' => 'UA']); - $this->assertSame('UA', $unifiedRequest->getUserAgent()); + self::assertSame('UA', $unifiedRequest->getUserAgent()); } } From 677e690a58f649127f423d23c88a385bdf57c883 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:42:30 +0200 Subject: [PATCH 22/38] Next --- tests/Matcher/ExtractorFactoryTest.php | 3 ++- tests/Matcher/StringMatcherTest.php | 4 +--- tests/MockBuilderIntegrationTest.php | 2 +- tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php | 2 +- tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/Matcher/ExtractorFactoryTest.php b/tests/Matcher/ExtractorFactoryTest.php index dcd4bc0..269d0b2 100644 --- a/tests/Matcher/ExtractorFactoryTest.php +++ b/tests/Matcher/ExtractorFactoryTest.php @@ -3,6 +3,7 @@ use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\Testing\AbstractTestCase; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\HttpFoundation\Request; class ExtractorFactoryTest extends AbstractTestCase @@ -15,7 +16,7 @@ class ExtractorFactoryTest extends AbstractTestCase public function setUp(): void { $this->extractorFactory = new ExtractorFactory(); - $this->request = $this->createMock('Symfony\Component\HttpFoundation\Request'); + $this->request = $this->createMock(Request::class); } public function testGetMethod(): void diff --git a/tests/Matcher/StringMatcherTest.php b/tests/Matcher/StringMatcherTest.php index fab4b12..374bb4a 100644 --- a/tests/Matcher/StringMatcherTest.php +++ b/tests/Matcher/StringMatcherTest.php @@ -10,9 +10,7 @@ class StringMatcherTest extends AbstractTestCase public function testConversionToString(): void { $matcher = new StringMatcher('0'); - $matcher->setExtractor(static function() { - return 0; - }); + $matcher->setExtractor(static fn () => 0); self::assertTrue($matcher->getMatcher()(new Request())); } } diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 31002b3..3a950d0 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -89,7 +89,7 @@ public function testCreateExpectation(): void self::assertSame('response body', (string) $client->post('/foo')->send()->getBody()); - self::assertTrue(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo') !== false); + self::assertNotFalse(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo')); } public function testCreateTwoExpectationsAfterEachOther(): void diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 4d8bf67..6b9e456 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -244,7 +244,7 @@ public function testPostRequest(): void public function testFatalError(): void { - if (version_compare(PHP_VERSION, '7.0', '<')) { + if (PHP_VERSION_ID < 70000) { self::markTestSkipped('Comment in to test if fatal errors are properly handled'); } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 472b0b9..bbba9ee 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -102,7 +102,7 @@ public function testErrorLogOutput(): void $this->tearDown(); self::fail('Exception expected'); } catch (\Exception $e) { - self::assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); + self::assertNotFalse(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty')); } } @@ -327,7 +327,7 @@ public function testMatchQueryParams(): void public function testFatalError(): void { - if (version_compare(PHP_VERSION, '7.0', '<')) { + if (PHP_VERSION_ID < 70000) { self::markTestSkipped('Comment in to test if fatal errors are properly handled'); } From 54da25f4cb6ea9b35b41bf6c73e019e250ecbaee Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:52:55 +0200 Subject: [PATCH 23/38] Portability --- tests/MockBuilderIntegrationTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 3a950d0..5ad069a 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -49,8 +49,8 @@ public function testCreateExpectation(): void }) ->then() ->statusCode(401) - ->body('response body') ->header('X-Foo', 'Bar') + ->body('response body') ->end(); self::assertSame($this->builder, $builder); @@ -79,8 +79,8 @@ public function testCreateExpectation(): void self::assertSame(3, $run); $expectation->getResponse()->setDate(new DateTime('2012-11-10 09:08:07', new DateTimeZone('UTC'))); - $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cache, private\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; - self::assertSame($response, (string)$expectation->getResponse()); + $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cache%s\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; + self::assertStringMatchesFormat($response, (string)$expectation->getResponse()); $this->server->setUp($expectations); From f9588793b1861afc47d3f1a54a45e7c78905a346 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 17:54:17 +0200 Subject: [PATCH 24/38] Next --- tests/MockBuilderIntegrationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 5ad069a..43ac455 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -79,7 +79,7 @@ public function testCreateExpectation(): void self::assertSame(3, $run); $expectation->getResponse()->setDate(new DateTime('2012-11-10 09:08:07', new DateTimeZone('UTC'))); - $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cache%s\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; + $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cach%s\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; self::assertStringMatchesFormat($response, (string)$expectation->getResponse()); From b2c67e7ca993ece01a36fabe90d0a43beae23516 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 11 May 2021 18:46:03 +0200 Subject: [PATCH 25/38] Newer Guzzle --- composer.json | 4 +- src/Request/UnifiedRequest.php | 295 ------------------ src/RequestCollectionFacade.php | 25 +- src/Server.php | 29 +- tests/AppIntegrationTest.php | 118 +++---- tests/MockBuilderIntegrationTest.php | 36 +-- .../HttpMockMultiPHPUnitIntegrationTest.php | 59 ++-- ...HttpMockPHPUnitIntegrationBasePathTest.php | 2 +- .../HttpMockPHPUnitIntegrationTest.php | 79 ++--- tests/Request/UnifiedRequestTest.php | 149 --------- tests/RequestCollectionFacadeTest.php | 39 +-- 11 files changed, 195 insertions(+), 640 deletions(-) delete mode 100644 src/Request/UnifiedRequest.php delete mode 100644 tests/Request/UnifiedRequestTest.php diff --git a/composer.json b/composer.json index 70ed472..7008694 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,11 @@ "require": { "php": "~7.4|~8.0", "silex/silex": "~2.0", - "guzzle/guzzle": ">=3.8", "symfony/process": "~3|~4|~5", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0", - "opis/closure": "^3.6" + "opis/closure": "^3.6", + "guzzlehttp/guzzle": "^7.3" }, "require-dev": { "internations/testing-component": "1.0.1", diff --git a/src/Request/UnifiedRequest.php b/src/Request/UnifiedRequest.php deleted file mode 100644 index a8f01cf..0000000 --- a/src/Request/UnifiedRequest.php +++ /dev/null @@ -1,295 +0,0 @@ - $params */ - public function __construct(RequestInterface $wrapped, array $params = []) - { - $this->wrapped = $wrapped; - $this->init($params); - } - - public function getUserAgent(): ?string - { - return $this->userAgent; - } - - /** - * Get the body of the request if set - * - */ - public function getBody(): ?EntityBodyInterface - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); - } - - /** - * Get a POST field from the request - * - * @param string $field Field to retrieve - * - * @return mixed|null - */ - public function getPostField(string $field) - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, [$field]); - } - - /** - * Get the post fields that will be used in the request - * - */ - public function getPostFields(): QueryString - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); - } - - /** - * Returns an associative array of POST field names to PostFileInterface objects - * - * @return array - */ - public function getPostFiles(): array - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__); - } - - /** - * Get a POST file from the request - * - * @param string $fieldName POST fields to retrieve - * - * @return array>|null Returns an array wrapping an array of PostFileInterface objects - */ - public function getPostFile(string $fieldName): ?array - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, [$fieldName]); - } - - /** - * Get application and plugin specific parameters set on the message. - * - */ - public function getParams(): Collection - { - return $this->wrapped->getParams(); - } - - /** - * Retrieve an HTTP header by name. Performs a case-insensitive search of all headers. - * - * @param string $header Header to retrieve. - * - * @return Header|null Returns NULL if no matching header is found. - * Returns a Header object if found. - */ - public function getHeader(string $header): ?Header - { - return $this->wrapped->getHeader($header); - } - - /** - * Get all headers as a collection - * - */ - public function getHeaders(): HeaderCollection - { - return $this->wrapped->getHeaders(); - } - - /** - * Get an array of message header lines - * - * @return array - */ - public function getHeaderLines(): array - { - return $this->wrapped->getHeaderLines(); - } - - /** - * Check if the specified header is present. - * - * @param string $header The header to check. - * - * @return bool Returns TRUE or FALSE if the header is present - */ - public function hasHeader(string $header): bool - { - return $this->wrapped->hasHeader($header); - } - - /** - * Get the raw message headers as a string - * - */ - public function getRawHeaders(): string - { - return $this->wrapped->getRawHeaders(); - } - - /** - * Get the collection of key value pairs that will be used as the query - * string in the request - * - */ - public function getQuery(): QueryString - { - return $this->wrapped->getQuery(); - } - - /** - * Get the HTTP method of the request - * - */ - public function getMethod(): string - { - return $this->wrapped->getMethod(); - } - - /** - * Get the URI scheme of the request (http, https, ftp, etc) - * - */ - public function getScheme(): string - { - return $this->wrapped->getScheme(); - } - - /** - * Get the host of the request - * - */ - public function getHost(): string - { - return $this->wrapped->getHost(); - } - - /** - * Get the HTTP protocol version of the request - * - */ - public function getProtocolVersion(): string - { - return $this->wrapped->getProtocolVersion(); - } - - /** - * Get the path of the request (e.g. '/', '/index.html') - * - */ - public function getPath(): string - { - return $this->wrapped->getPath(); - } - - /** - * Get the port that the request will be sent on if it has been set - * - */ - public function getPort(): ?int - { - return $this->wrapped->getPort(); - } - - /** - * Get the username to pass in the URL if set - * - */ - public function getUsername(): ?string - { - return $this->wrapped->getUsername(); - } - - /** - * Get the password to pass in the URL if set - * - */ - public function getPassword(): ?string - { - return $this->wrapped->getPassword(); - } - - /** - * Get the full URL of the request (e.g. 'http://www.guzzle-project.com/') - * scheme://username:password@domain:port/path?query_string#fragment - * - * @param bool $asObject Set to TRUE to retrieve the URL as a clone of the URL object owned by the request. - * - * @return string|Url - */ - public function getUrl(bool $asObject = false) - { - return $this->wrapped->getUrl($asObject); - } - - /** - * Get an array of Cookies - * - * @return array - */ - public function getCookies(): array - { - return $this->wrapped->getCookies(); - } - - /** - * Get a cookie value by name - * - * @param string $name Cookie to retrieve - * - */ - public function getCookie(string $name): ?string - { - return $this->wrapped->getCookie($name); - } - - /** - * @param array $params - * @return mixed - */ - protected function invokeWrappedIfEntityEnclosed(string $method, array $params = []) - { - if (!$this->wrapped instanceof EntityEnclosingRequestInterface) { - throw new BadMethodCallException( - sprintf( - 'Cannot call method "%s" on a request that does not enclose an entity.' - . ' Did you expect a POST/PUT request instead of %s %s?', - $method, - $this->wrapped->getMethod(), - $this->wrapped->getPath() - ) - ); - } - - return call_user_func_array([$this->wrapped, $method], $params); - } - - /** @param array $params */ - private function init(array $params): void - { - foreach ($params as $property => $value) { - if (!property_exists($this, $property)) { - continue; - } - - $this->{$property} = $value; - } - } -} diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index 39eded3..b7c5ace 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -2,16 +2,16 @@ namespace InterNations\Component\HttpMock; use Countable; -use Guzzle\Http\ClientInterface; -use Guzzle\Http\Message\Response; +use GuzzleHttp\Client; +use GuzzleHttp\Psr7\Response; use Symfony\Component\HttpFoundation\Request; use UnexpectedValueException; class RequestCollectionFacade implements Countable { - private ClientInterface $client; + private Client $client; - public function __construct(ClientInterface $client) + public function __construct(Client $client) { $this->client = $client; } @@ -49,10 +49,9 @@ public function shift(): Request public function count(): int { $response = $this->client - ->get('/_request/count') - ->send(); + ->get('/_request/count'); - return (int) $response->getBody(true); + return (int) (string) $response->getBody(); } /** @@ -73,25 +72,21 @@ private function parseRequestFromResponse(Response $response, string $path): Req private function getRecordedRequest(string $path): Request { - $response = $this->client - ->get($path) - ->send(); + $response = $this->client->get($path); return $this->parseResponse($response, $path); } private function deleteRecordedRequest(string $path): Request { - $response = $this->client - ->delete($path) - ->send(); + $response = $this->client->delete($path); return $this->parseResponse($response, $path); } private function parseResponse(Response $response, string $path): Request { - $statusCode = (int) $response->getStatusCode(); + $statusCode = $response->getStatusCode(); if ($statusCode !== 200) { throw new UnexpectedValueException( @@ -100,7 +95,7 @@ private function parseResponse(Response $response, string $path): Request } $contentType = $response->hasHeader('content-type') - ? $response->getContentType() + ? $response->getHeaderLine('content-type') : ''; if (strpos($contentType, 'text/plain') !== 0) { diff --git a/src/Server.php b/src/Server.php index 82474d6..b23bfdd 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1,12 +1,10 @@ getBaseUrl()); - $client->getEventDispatcher()->addListener( - 'request.error', - static function (Event $event): void { - $event->stopPropagation(); - } - ); - - return $client; + return new Client(['base_uri' => $this->getBaseUrl(), 'http_errors' => false]); } public function getBaseUrl(): string @@ -88,13 +78,14 @@ public function setUp(array $expectations): void foreach ($expectations as $expectation) { $response = $this->getClient()->post( '/_expectation', - null, [ - 'matcher' => serialize($expectation->getMatcherClosures()), - 'limiter' => serialize($expectation->getLimiter()), - 'response' => serialize($expectation->getResponse()), + 'form_params' => [ + 'matcher' => serialize($expectation->getMatcherClosures()), + 'limiter' => serialize($expectation->getLimiter()), + 'response' => serialize($expectation->getResponse()), + ], ] - )->send(); + ); if ($response->getStatusCode() !== 201) { throw new RuntimeException('Could not set up expectations'); @@ -108,7 +99,7 @@ public function clean(): void $this->start(); } - $this->getClient()->delete('/_all')->send(); + $this->getClient()->delete('/_all'); } private function pollWait(): void @@ -116,7 +107,7 @@ private function pollWait(): void foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) { try { usleep($sleepTime); - $this->getClient()->head('/_me')->send(); + $this->getClient()->head('/_me'); break; } catch (CurlException $e) { continue; diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index ef673eb..d79084b 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -6,10 +6,11 @@ use InterNations\Component\HttpMock\Server; use InterNations\Component\HttpMock\Util; use InterNations\Component\Testing\AbstractTestCase; -use Guzzle\Http\Client; +use GuzzleHttp\Client; use Guzzle\Http\Message\RequestFactory; use Guzzle\Http\Message\Response as GuzzleResponse; use Opis\Closure\SerializableClosure; +use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -46,27 +47,28 @@ public function testSimpleUseCase(): void { $response = $this->client->post( '/_expectation', - null, - $this->createExpectationParams( + ['form_params' => $this->createExpectationParams( [ static function ($request) { return $request instanceof Request; }, ], new Response('fake body', 200) - ) - )->send(); + )] + ); self::assertSame('', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - $response = $this->client->post('/foobar', ['X-Special' => 1], ['post' => 'data'])->send(); + $response = $this->client->post( + '/foobar', + ['headers' => ['X-Special' => 1], 'form_params' => ['post' => 'data']] + ); self::assertSame(200, $response->getStatusCode()); self::assertSame('fake body', (string) $response->getBody()); - $response = $this->client->get('/_request/latest')->send(); + $response = $this->client->get('/_request/latest'); - /** @var Request $request */ $request = $this->parseRequestFromResponse($response); self::assertSame('1', (string) $request->headers->get('X-Special')); self::assertSame('post=data', $request->getContent()); @@ -74,80 +76,80 @@ static function ($request) { public function testRecording(): void { - $this->client->delete('/_all')->send(); + $this->client->delete('/_all'); - self::assertSame(404, $this->client->get('/_request/latest')->send()->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/0')->send()->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/first')->send()->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/last')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/latest')->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/0')->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/first')->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/last')->getStatusCode()); - $this->client->get('/req/0')->send(); - $this->client->get('/req/1')->send(); - $this->client->get('/req/2')->send(); - $this->client->get('/req/3')->send(); + $this->client->get('/req/0'); + $this->client->get('/req/1'); + $this->client->get('/req/2'); + $this->client->get('/req/3'); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/last'))->getRequestUri() ); self::assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/0'))->getRequestUri() ); self::assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/1'))->getRequestUri() ); self::assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/2'))->getRequestUri() ); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/3'))->getRequestUri() ); - self::assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/4')->getStatusCode()); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->delete('/_request/last'))->getRequestUri() ); self::assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->delete('/_request/first'))->getRequestUri() ); self::assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/0'))->getRequestUri() ); self::assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getRequestUri() + $this->parseRequestFromResponse($this->client->get('/_request/1'))->getRequestUri() ); - self::assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); + self::assertSame(404, $this->client->get('/_request/2')->getStatusCode()); } public function testErrorHandling(): void { - $this->client->delete('/_all')->send(); + $this->client->delete('/_all'); - $response = $this->client->post('/_expectation', null, ['matcher' => ''])->send(); + $response = $this->client->post('/_expectation', ['form_params' => ['matcher' => '']]); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['matcher' => ['foo']])->send(); + $response = $this->client->post('/_expectation', ['form_params' => ['matcher' => ['foo']]]); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, [])->send(); + $response = $this->client->post('/_expectation'); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "response" not found in POST data', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['response' => ''])->send(); + $response = $this->client->post('/_expectation', ['form_params' => ['response' => '']]); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "response" must be a serialized Symfony response', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['response' => serialize(new Response()), 'limiter' => 'foo'])->send(); + $response = $this->client->post('/_expectation', ['form_params' => ['response' => serialize(new Response()), 'limiter' => 'foo']]); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } @@ -156,31 +158,33 @@ public function testNewestExpectationsAreFirstEvaluated(): void { $this->client->post( '/_expectation', - null, - $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - }, - ], - new Response('first', 200) - ) - )->send(); - self::assertSame('first', $this->client->get('/')->send()->getBody(true)); + [ + 'form_params' => $this->createExpectationParams( + [ + static function ($request) { + return $request instanceof Request; + }, + ], + new Response('first', 200) + ), + ] + ); + self::assertSame('first', (string) $this->client->get('/')->getBody()); $this->client->post( '/_expectation', - null, - $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - }, - ], - new Response('second', 200) - ) - )->send(); - self::assertSame('second', $this->client->get('/')->send()->getBody(true)); + [ + 'form_params' => $this->createExpectationParams( + [ + static function ($request) { + return $request instanceof Request; + }, + ], + new Response('second', 200) + ), + ] + ); + self::assertSame('second', (string) $this->client->get('/')->getBody()); } public function testServerLogsAreNotInErrorOutput(): void @@ -201,7 +205,7 @@ public function testServerLogsAreNotInErrorOutput(): void self::$server1->clearErrorOutput(); } - private function parseRequestFromResponse(GuzzleResponse $response): Request + private function parseRequestFromResponse(ResponseInterface $response): Request { return Util::deserialize($response->getBody()); } diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 43ac455..c17d8c0 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -87,7 +87,7 @@ public function testCreateExpectation(): void $client = $this->server->getClient(); - self::assertSame('response body', (string) $client->post('/foo')->send()->getBody()); + self::assertSame('response body', (string) $client->post('/foo')->getBody()); self::assertNotFalse(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo')); } @@ -114,10 +114,10 @@ public function testCreateTwoExpectationsAfterEachOther(): void ->end(); $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); - self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); + self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); + self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); + self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); + self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); } public function testCreateSuccessiveExpectationsOnSameWhen(): void @@ -146,9 +146,9 @@ public function testCreateSuccessiveExpectationsOnSameWhen(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('called once', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('called twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('called once', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('called twice', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->getBody()); } public function testCreateSuccessiveExpectationsWithAny(): void @@ -177,9 +177,9 @@ public function testCreateSuccessiveExpectationsWithAny(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('any', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('any', (string) $this->server->getClient()->post('/resource')->getBody()); } public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void @@ -201,8 +201,8 @@ public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); } public function testCreateSuccessiveExpectationsWithOnce(): void @@ -231,10 +231,10 @@ public function testCreateSuccessiveExpectationsWithOnce(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->send()->getBody()); - self::assertSame('Expectation not met', (string) $this->server->getClient()->post('/resource')->send()->getBody()); + self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('Expectation not met', (string) $this->server->getClient()->post('/resource')->getBody()); } } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 6b9e456..cb2da91 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -52,7 +52,7 @@ public function testSimpleRequest(string $path): void ->end(); $this->http['firstNamedServer']->setUp(); - self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); $request = $this->http['firstNamedServer']->requests->latest(); self::assertSame('GET', $request->getMethod()); @@ -74,7 +74,7 @@ public function testSimpleRequest(string $path): void self::assertSame('GET', $request->getMethod()); self::assertSame($path, $request->getRequestUri()); - self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); $request = $this->http['firstNamedServer']->requests->shift(); self::assertSame('GET', $request->getMethod()); @@ -95,7 +95,7 @@ public function testErrorLogOutput(): void ->end(); $this->http['firstNamedServer']->setUp(); - $this->http['firstNamedServer']->client->get('/foo')->send(); + $this->http['firstNamedServer']->client->get('/foo'); // Should fail during tear down as we have an error_log() on the server side try { @@ -108,7 +108,7 @@ public function testErrorLogOutput(): void public function testFailedRequest(): void { - $response = $this->http['firstNamedServer']->client->get('/foo')->send(); + $response = $this->http['firstNamedServer']->client->get('/foo'); self::assertSame(404, $response->getStatusCode()); self::assertSame('No matching expectation found', (string) $response->getBody()); } @@ -121,7 +121,7 @@ public function testStopServer(): void /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt(): void { - $response = $this->http['firstNamedServer']->client->get('/')->send(); + $response = $this->http['firstNamedServer']->client->get('/'); self::assertSame(404, $response->getStatusCode()); } @@ -135,11 +135,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(410, $secondResponse->getStatusCode()); - self::assertSame('Expectation not met', $secondResponse->getBody(true)); + self::assertSame('Expectation not met', (string) $secondResponse->getBody()); $this->http['firstNamedServer']->mock ->exactly(2) @@ -149,13 +149,13 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $thirdResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(410, $thirdResponse->getStatusCode()); - self::assertSame('Expectation not met', $thirdResponse->getBody(true)); + self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); $this->http['firstNamedServer']->mock ->any() @@ -165,11 +165,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $thirdResponse = $this->http['firstNamedServer']->client->post('/'); self::assertSame(200, $thirdResponse->getStatusCode()); } @@ -182,7 +182,7 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http['firstNamedServer']->setUp(); - self::assertSame('CALLBACK', $this->http['firstNamedServer']->client->post('/')->send()->getBody(true)); + self::assertSame('CALLBACK', (string) $this->http['firstNamedServer']->client->post('/')->getBody()); } public function testComplexResponse(): void @@ -197,10 +197,13 @@ public function testComplexResponse(): void ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->post( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', $response->getHeaderLine('X-Foo')); self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } @@ -216,10 +219,13 @@ public function testPutRequest(): void ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->put( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['put-key' => 'put-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); self::assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->request->get('put-key')); } @@ -235,10 +241,13 @@ public function testPostRequest(): void ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->post( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', $response->getHeaderLine('X-Foo')); self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key')); } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index f3ca0ef..f7a3baf 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -39,7 +39,7 @@ public function testSimpleRequest(): void ->end(); $this->http->setUp(); - self::assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->send()->getBody()); + self::assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->getBody()); $request = $this->http->requests->latest(); self::assertSame('GET', $request->getMethod()); diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index bbba9ee..9842bc3 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -52,7 +52,7 @@ public function testSimpleRequest(string $path): void ->end(); $this->http->setUp(); - self::assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); $request = $this->http->requests->latest(); self::assertSame('GET', $request->getMethod()); @@ -74,7 +74,7 @@ public function testSimpleRequest(string $path): void self::assertSame('GET', $request->getMethod()); self::assertSame($path, $request->getRequestUri()); - self::assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + self::assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); $request = $this->http->requests->shift(); self::assertSame('GET', $request->getMethod()); @@ -95,7 +95,7 @@ public function testErrorLogOutput(): void ->end(); $this->http->setUp(); - $this->http->client->get('/foo')->send(); + $this->http->client->get('/foo'); // Should fail during tear down as we have an error_log() on the server side try { @@ -108,7 +108,7 @@ public function testErrorLogOutput(): void public function testFailedRequest(): void { - $response = $this->http->client->get('/foo')->send(); + $response = $this->http->client->get('/foo'); self::assertSame(404, $response->getStatusCode()); self::assertSame('No matching expectation found', (string) $response->getBody()); } @@ -121,7 +121,7 @@ public function testStopServer(): void /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt(): void { - $response = $this->http->client->get('/')->send(); + $response = $this->http->client->get('/'); self::assertSame(404, $response->getStatusCode()); } @@ -135,11 +135,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); self::assertSame(410, $secondResponse->getStatusCode()); - self::assertSame('Expectation not met', $secondResponse->getBody(true)); + self::assertSame('Expectation not met', (string) $secondResponse->getBody()); $this->http->mock ->exactly(2) @@ -149,13 +149,13 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/')->send(); + $thirdResponse = $this->http->client->post('/'); self::assertSame(410, $thirdResponse->getStatusCode()); - self::assertSame('Expectation not met', $thirdResponse->getBody(true)); + self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); $this->http->mock ->any() @@ -165,11 +165,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/')->send(); + $thirdResponse = $this->http->client->post('/'); self::assertSame(200, $thirdResponse->getStatusCode()); } @@ -182,7 +182,7 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http->setUp(); - self::assertSame('CALLBACK', $this->http->client->post('/')->send()->getBody(true)); + self::assertSame('CALLBACK', (string) $this->http->client->post('/')->getBody()); } public function testComplexResponse(): void @@ -197,10 +197,13 @@ public function testComplexResponse(): void ->end(); $this->http->setUp(); $response = $this->http->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->post( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } @@ -216,10 +219,13 @@ public function testPutRequest(): void ->end(); $this->http->setUp(); $response = $this->http->client - ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->put( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['put-key' => 'put-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', $response->getHeaderLine('X-Foo')); self::assertSame('put-value', $this->http->requests->latest()->request->get('put-key')); } @@ -235,10 +241,13 @@ public function testPostRequest(): void ->end(); $this->http->setUp(); $response = $this->http->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - self::assertSame('BODY', $response->getBody(true)); + ->post( + '/', + ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] + ); + self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeader('X-Foo')); + self::assertSame('Bar', $response->getHeaderLine('X-Foo')); self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } @@ -253,7 +262,7 @@ public function testCountRequests(): void $this->http->setUp(); self::assertCount(0, $this->http->requests); - self::assertSame('resource body', (string) $this->http->client->get('/resource')->send()->getBody()); + self::assertSame('resource body', (string) $this->http->client->get('/resource')->getBody()); self::assertCount(1, $this->http->requests); } @@ -272,10 +281,10 @@ static function (Request $request) { ->end(); $this->http->setUp(); - self::assertSame('query string', (string) $this->http->client->get('/?key1=')->send()->getBody()); + self::assertSame('query string', (string) $this->http->client->get('/?key1=')->getBody()); - self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->get('/')->send()->getStatusCode()); - self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->send()->getStatusCode()); + self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->get('/')->getStatusCode()); + self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->getStatusCode()); } public function testMatchRegex(): void @@ -288,8 +297,8 @@ public function testMatchRegex(): void ->end(); $this->http->setUp(); - self::assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); - self::assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); + self::assertSame('response', (string) $this->http->client->get('/')->getBody()); + self::assertSame('response', (string) $this->http->client->get('/')->getBody()); } public function testMatchQueryParams(): void @@ -309,19 +318,19 @@ public function testMatchQueryParams(): void self::assertSame( 'response', - (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->send()->getBody() + (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->getBody() ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p1=&p2=v2&p3=foo')->send()->getStatusCode() + $this->http->client->get('/?p1=&p2=v2&p3=foo')->getStatusCode() ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p1=')->send()->getStatusCode() + $this->http->client->get('/?p1=')->getStatusCode() ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p3=foo')->send()->getStatusCode() + $this->http->client->get('/?p3=foo')->getStatusCode() ); } diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php deleted file mode 100644 index 89992c7..0000000 --- a/tests/Request/UnifiedRequestTest.php +++ /dev/null @@ -1,149 +0,0 @@ -wrappedRequest = $this->createMock(RequestInterface::class); - $this->wrappedEntityEnclosingRequest = $this->createMock(EntityEnclosingRequestInterface::class); - $this->unifiedRequest = new UnifiedRequest($this->wrappedRequest); - $this->unifiedEnclosingEntityRequest = new UnifiedRequest($this->wrappedEntityEnclosingRequest); - } - - /** @return array,2:mixed}>> */ - public static function provideMethods(): array - { - return [ - ['getParams', [], new Collection()], - ['getHeaders', [], new HeaderCollection()], - ['getHeaderLines', [], ['Foo' => 'Bar']], - ['getRawHeaders'], - ['getQuery', [], new QueryString()], - ['getMethod'], - ['getScheme'], - ['getHost'], - ['getProtocolVersion'], - ['getPath'], - ['getPort', [], 8080], - ['getUsername'], - ['getPassword'], - ['getUrl'], - ['getCookies', [], []], - ['getHeader', ['header'], new Header('Foo', 'Bar')], - ['hasHeader', ['header'], true], - ['getUrl', [false]], - ['getUrl', [true]], - ['getCookie', ['cookieName']], - ]; - } - - /** @return array,2:mixed}>> */ - public static function provideEntityEnclosingInterfaceMethods(): array - { - return [ - ['getBody', [], EntityBody::fromString('foo')], - ['getPostField', ['postField']], - ['getPostFields', [], new QueryString()], - ['getPostFiles', [], []], - ['getPostFile', ['fileName'], []], - ]; - } - - /** - * @dataProvider provideMethods - * @param array $params - * @param mixed $returnValue - */ - public function testMethodsFromRequestInterface(string $method, array $params = [], $returnValue = 'REQ'): void - { - $this->wrappedRequest - ->expects(self::once()) - ->method($method) - ->willReturn($returnValue) - ->with(...$params); - self::assertSame($returnValue, call_user_func_array([$this->unifiedRequest, $method], $params)); - - - $this->wrappedEntityEnclosingRequest - ->expects(self::once()) - ->method($method) - ->willReturn($returnValue) - ->with(...$params); - self::assertSame( - $returnValue, - call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) - ); - } - - /** - * @dataProvider provideEntityEnclosingInterfaceMethods - * @param array $params - * @param mixed $returnValue - */ - public function testEntityEnclosingInterfaceMethods( - string $method, - array $params = [], - $returnValue = 'Return Value' - ): void - { - $this->wrappedEntityEnclosingRequest - ->expects(self::once()) - ->method($method) - ->willReturn($returnValue) - ->with(...$params); - - self::assertSame( - $returnValue, - call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) - ); - - $this->wrappedRequest - ->method('getMethod') - ->willReturn('METHOD'); - $this->wrappedRequest - ->method('getPath') - ->willReturn('/foo'); - - $this->expectException('BadMethodCallException'); - - $this->expectExceptionMessage( - - sprintf( - 'Cannot call method "%s" on a request that does not enclose an entity. Did you expect a POST/PUT request instead of METHOD /foo?', - $method - ) - - ); - call_user_func_array([$this->unifiedRequest, $method], $params); - } - - public function testUserAgent(): void - { - self::assertNull($this->unifiedRequest->getUserAgent()); - - $unifiedRequest = new UnifiedRequest($this->wrappedRequest, ['userAgent' => 'UA']); - self::assertSame('UA', $unifiedRequest->getUserAgent()); - } -} diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index 4a39704..7f373d2 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -1,29 +1,25 @@ client = $this->createMock(ClientInterface::class); + $this->client = $this->createMock(Client::class); $this->facade = new RequestCollectionFacade($this->client); - $this->request = new Request('GET', '/_request/last'); - $this->request->setClient($this->client); } /** @return array,3:string}> */ @@ -52,7 +48,8 @@ public function testRequestingLatestRequest( { $this->mockClient($path, $this->createSimpleResponse(), $httpMethod); - $request = call_user_func_array([$this->facade, $method], $args); + /** @var \Symfony\Component\HttpFoundation\Request $request */ + $request = $this->facade->{$method}(...$args); self::assertSame('POST', $request->getMethod()); self::assertSame('/foo', $request->getRequestUri()); @@ -73,7 +70,7 @@ public function testRequestLatestResponseWithHttpAuth( $this->mockClient($path, $this->createComplexResponse(), $httpMethod); /** @var \Symfony\Component\HttpFoundation\Request $request */ - $request = call_user_func_array([$this->facade, $method], $args); + $request = $this->facade->{$method}(...$args); self::assertSame('POST', $request->getMethod()); self::assertSame('/foo', $request->getRequestUri()); @@ -161,22 +158,16 @@ public function testRequestResponseWithDeserializationError( call_user_func_array([$this->facade, $method], $args); } - private function mockClient(string $path, Response $response, string $method): void + private function mockClient(string $path, ResponseInterface $response, string $method): void { $this->client ->expects(self::once()) ->method($method) ->with($path) - ->willReturn($this->request); - - $this->client - ->expects(self::once()) - ->method('send') - ->with($this->request) ->willReturn($response); } - private function createSimpleResponse(): Response + private function createSimpleResponse(): ResponseInterface { $recordedRequest = new TestRequest(); $recordedRequest->setMethod('POST'); @@ -190,7 +181,7 @@ private function createSimpleResponse(): Response ); } - private function createComplexResponse(): Response + private function createComplexResponse(): ResponseInterface { $recordedRequest = new TestRequest(); $recordedRequest->setMethod('POST'); @@ -210,22 +201,22 @@ private function createComplexResponse(): Response ); } - private function createResponseWithInvalidStatusCode(): Response + private function createResponseWithInvalidStatusCode(): ResponseInterface { return new Response(404); } - private function createResponseWithInvalidContentType(): Response + private function createResponseWithInvalidContentType(): ResponseInterface { return new Response(200, ['Content-Type' => 'text/html']); } - private function createResponseWithEmptyContentType(): Response + private function createResponseWithEmptyContentType(): ResponseInterface { return new Response(200, []); } - private function createResponseThatCannotBeDeserialized(): Response + private function createResponseThatCannotBeDeserialized(): ResponseInterface { return new Response(200, ['Content-Type' => 'text/plain'], 'invalid response'); } From dc3d98775b2faaa84461a33e48caa8dccc5d566d Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 12 May 2021 15:56:36 +0200 Subject: [PATCH 26/38] PSR initial port --- composer.json | 6 +- src/Http/BaseUriMiddleware.php | 31 +++ src/Http/ClientMiddleware.php | 11 + src/Http/EmptyMiddleware.php | 14 ++ src/Http/MiddlewareSupportingClient.php | 31 +++ src/PHPUnit/HttpMockFacade.php | 6 +- src/RequestCollectionFacade.php | 34 +-- src/Server.php | 72 ++++-- tests/AppIntegrationTest.php | 219 +++++++++++------- tests/MockBuilderIntegrationTest.php | 100 ++++++-- .../HttpMockMultiPHPUnitIntegrationTest.php | 102 +++++--- ...HttpMockPHPUnitIntegrationBasePathTest.php | 10 +- .../HttpMockPHPUnitIntegrationTest.php | 133 +++++++---- tests/RequestCollectionFacadeTest.php | 55 +++-- tests/TestCase.php | 26 +++ 15 files changed, 611 insertions(+), 239 deletions(-) create mode 100644 src/Http/BaseUriMiddleware.php create mode 100644 src/Http/ClientMiddleware.php create mode 100644 src/Http/EmptyMiddleware.php create mode 100644 src/Http/MiddlewareSupportingClient.php create mode 100644 tests/TestCase.php diff --git a/composer.json b/composer.json index 7008694..e5a0bce 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,11 @@ "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0", "opis/closure": "^3.6", - "guzzlehttp/guzzle": "^7.3" + "guzzlehttp/guzzle": "^7.3", + "psr/http-factory": "^1.0", + "guzzlehttp/psr7": "^1.8", + "http-interop/http-factory-guzzle": "^1.0", + "php-http/discovery": "^1.13" }, "require-dev": { "internations/testing-component": "1.0.1", diff --git a/src/Http/BaseUriMiddleware.php b/src/Http/BaseUriMiddleware.php new file mode 100644 index 0000000..c9515e0 --- /dev/null +++ b/src/Http/BaseUriMiddleware.php @@ -0,0 +1,31 @@ +baseUri = $baseUri; + } + + public function process(RequestInterface $request, ClientInterface $client, callable $next): ResponseInterface + { + $originalUri = $request->getUri(); + + $uri = $originalUri + ->withScheme($this->baseUri->getScheme() ?: $originalUri->getScheme()) + ->withHost($this->baseUri->getHost() ?: $originalUri->getHost()) + ->withPort($this->baseUri->getPort() ?: $originalUri->getPort()) + ->withPath(sprintf('%s/%s', rtrim($this->baseUri->getPath(), '/'), ltrim($originalUri->getPath(), '/'))); + + + return $next($request->withUri($uri), $client); + } +} diff --git a/src/Http/ClientMiddleware.php b/src/Http/ClientMiddleware.php new file mode 100644 index 0000000..8acc474 --- /dev/null +++ b/src/Http/ClientMiddleware.php @@ -0,0 +1,11 @@ +sendRequest($request); + } +} diff --git a/src/Http/MiddlewareSupportingClient.php b/src/Http/MiddlewareSupportingClient.php new file mode 100644 index 0000000..7daddf8 --- /dev/null +++ b/src/Http/MiddlewareSupportingClient.php @@ -0,0 +1,31 @@ +client = $client; + $this->middlewareStack = array_merge([new EmptyMiddleware()], $middlewareStack); + } + + public function sendRequest(RequestInterface $request): ResponseInterface + { + $middlewareStack = $this->middlewareStack; + + $next = static function(RequestInterface $request, ClientInterface $client) use (&$middlewareStack, &$next) { + $middleware = array_pop($middlewareStack); + return $middleware->process($request, $client, $next); + }; + + return $next($request, $this->client); + } +} diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index c484b4b..c42e2f0 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -2,11 +2,13 @@ namespace InterNations\Component\HttpMock\PHPUnit; use Guzzle\Http\Client; +use Http\Discovery\Psr17FactoryDiscovery; use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\MockBuilder; use InterNations\Component\HttpMock\RequestCollectionFacade; use InterNations\Component\HttpMock\Server; +use Psr\Http\Client\ClientInterface; use RuntimeException; /** @@ -14,7 +16,7 @@ * @property-read MatcherFactory $matches An instance of the matcher factory * @property-read MockBuilder $mock An instance of the mock builder * @property-read RequestCollectionFacade $requests Convenient access to recorded requests - * @property-read Client $client A pre configured HTTP for client for the currently running server + * @property-read ClientInterface $client A pre configured HTTP for client for the currently running server */ class HttpMockFacade { @@ -60,7 +62,7 @@ private function createService(string $property): object return $this->server->getClient(); case 'requests': - return new RequestCollectionFacade($this->client); + return new RequestCollectionFacade($this->client, Psr17FactoryDiscovery::findRequestFactory()); default: throw new RuntimeException(sprintf('Invalid property "%s" read', $property)); diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index b7c5ace..43f422c 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -4,16 +4,21 @@ use Countable; use GuzzleHttp\Client; use GuzzleHttp\Psr7\Response; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Request; use UnexpectedValueException; class RequestCollectionFacade implements Countable { - private Client $client; + private ClientInterface $client; + private RequestFactoryInterface $requestFactory; - public function __construct(Client $client) + public function __construct(ClientInterface $client, RequestFactoryInterface $requestFactory) { $this->client = $client; + $this->requestFactory = $requestFactory; } public function latest(): Request @@ -48,10 +53,9 @@ public function shift(): Request public function count(): int { - $response = $this->client - ->get('/_request/count'); - - return (int) (string) $response->getBody(); + return (int) (string) $this->client->sendRequest( + $this->requestFactory->createRequest('GET', '/_request/count') + )->getBody(); } /** @@ -72,16 +76,18 @@ private function parseRequestFromResponse(Response $response, string $path): Req private function getRecordedRequest(string $path): Request { - $response = $this->client->get($path); - - return $this->parseResponse($response, $path); + return $this->parseResponse( + $this->client->sendRequest($this->requestFactory->createRequest('GET', $path)), + $path + ); } private function deleteRecordedRequest(string $path): Request { - $response = $this->client->delete($path); - - return $this->parseResponse($response, $path); + return $this->parseResponse( + $this->client->sendRequest($this->requestFactory->createRequest('DELETE', $path)), + $path + ); } private function parseResponse(Response $response, string $path): Request @@ -94,9 +100,7 @@ private function parseResponse(Response $response, string $path): Request ); } - $contentType = $response->hasHeader('content-type') - ? $response->getHeaderLine('content-type') - : ''; + $contentType = $response->getHeaderLine('content-type'); if (strpos($contentType, 'text/plain') !== 0) { throw new UnexpectedValueException( diff --git a/src/Server.php b/src/Server.php index b23bfdd..599e683 100644 --- a/src/Server.php +++ b/src/Server.php @@ -3,6 +3,18 @@ use GuzzleHttp\Client; use hmmmath\Fibonacci\FibonacciFactory; +use Http\Discovery\Psr17FactoryDiscovery; +use Http\Discovery\Psr18ClientDiscovery; +use InterNations\Component\HttpMock\Http\BaseUriMiddleware; +use InterNations\Component\HttpMock\Http\MiddlewareSupportingClient; +use Psr\Http\Client\ClientExceptionInterface; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UriFactoryInterface; +use Psr\Http\Message\UriInterface; use Symfony\Component\Process\Process; use RuntimeException; @@ -12,7 +24,7 @@ class Server extends Process private string $host; - private ?Client $client = null; + private ?ClientInterface $client = null; public function __construct(int $port, string $host) { @@ -49,19 +61,37 @@ public function stop($timeout = 10, $signal = null): ?int // @codingStandardsIgn return parent::stop($timeout, $signal); } - public function getClient(): Client + public function getClient(): ClientInterface { return $this->client ?: $this->client = $this->createClient(); } - private function createClient(): Client + private function createClient(): ClientInterface { - return new Client(['base_uri' => $this->getBaseUrl(), 'http_errors' => false]); + return new MiddlewareSupportingClient( + Psr18ClientDiscovery::find(), + new BaseUriMiddleware($this->getBaseUrl()) + ); } - public function getBaseUrl(): string + public function getBaseUrl(): UriInterface { - return sprintf('http://%s', $this->getConnectionString()); + return $this->getUriFactory()->createUri(sprintf('http://%s', $this->getConnectionString())); + } + + private function getUriFactory(): UriFactoryInterface + { + return Psr17FactoryDiscovery::findUriFactory(); + } + + private function getRequestFactory(): RequestFactoryInterface + { + return Psr17FactoryDiscovery::findRequestFactory(); + } + + private function getStreamFactory(): StreamFactoryInterface + { + return Psr17FactoryDiscovery::findStreamFactory(); } public function getConnectionString(): string @@ -76,15 +106,21 @@ public function getConnectionString(): string public function setUp(array $expectations): void { foreach ($expectations as $expectation) { - $response = $this->getClient()->post( - '/_expectation', - [ - 'form_params' => [ - 'matcher' => serialize($expectation->getMatcherClosures()), - 'limiter' => serialize($expectation->getLimiter()), - 'response' => serialize($expectation->getResponse()), - ], - ] + $response = $this->getClient()->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query( + [ + 'matcher' => serialize($expectation->getMatcherClosures()), + 'limiter' => serialize($expectation->getLimiter()), + 'response' => serialize($expectation->getResponse()), + ] + ) + ) + ) ); if ($response->getStatusCode() !== 201) { @@ -99,7 +135,7 @@ public function clean(): void $this->start(); } - $this->getClient()->delete('/_all'); + $this->getClient()->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all')); } private function pollWait(): void @@ -107,9 +143,9 @@ private function pollWait(): void foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) { try { usleep($sleepTime); - $this->getClient()->head('/_me'); + $this->getClient()->sendRequest($this->getRequestFactory()->createRequest('HEAD', '/_me')); break; - } catch (CurlException $e) { + } catch (ClientExceptionInterface $e) { continue; } } diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index d79084b..35399eb 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -5,24 +5,23 @@ use Guzzle\Http\Message\RequestInterface; use InterNations\Component\HttpMock\Server; use InterNations\Component\HttpMock\Util; -use InterNations\Component\Testing\AbstractTestCase; -use GuzzleHttp\Client; use Guzzle\Http\Message\RequestFactory; -use Guzzle\Http\Message\Response as GuzzleResponse; use Opis\Closure\SerializableClosure; +use Psr\Http\Client\ClientInterface; use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use function http_build_query; /** * @large * @group integration */ -class AppIntegrationTest extends AbstractTestCase +class AppIntegrationTest extends TestCase { private static Server $server1; - private Client $client; + private ClientInterface $client; public static function setUpBeforeClass(): void { @@ -33,7 +32,11 @@ public static function setUpBeforeClass(): void public static function tearDownAfterClass(): void { static::assertSame('', (string) static::$server1->getOutput(), (string) static::$server1->getOutput()); - static::assertSame('', (string) static::$server1->getErrorOutput(), (string) static::$server1->getErrorOutput()); + static::assertSame( + '', + (string) static::$server1->getErrorOutput(), + (string) static::$server1->getErrorOutput() + ); static::$server1->stop(); } @@ -45,151 +48,207 @@ public function setUp(): void public function testSimpleUseCase(): void { - $response = $this->client->post( - '/_expectation', - ['form_params' => $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - }, - ], - new Response('fake body', 200) - )] + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query( + $this->createExpectationParams( + [ + static function ($request) { + return $request instanceof Request; + }, + ], + new Response('fake body', 200) + ) + ) + ) + ) ); self::assertSame('', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - $response = $this->client->post( - '/foobar', - ['headers' => ['X-Special' => 1], 'form_params' => ['post' => 'data']] + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/foobar') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('X-Special', 1) + ->withBody($this->getStreamFactory()->createStream(http_build_query(['post' => 'data']))) ); self::assertSame(200, $response->getStatusCode()); self::assertSame('fake body', (string) $response->getBody()); - $response = $this->client->get('/_request/latest'); + $response = $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/latest')); $request = $this->parseRequestFromResponse($response); - self::assertSame('1', (string) $request->headers->get('X-Special')); + self::assertSame('1', $request->headers->get('X-Special')); self::assertSame('post=data', $request->getContent()); } public function testRecording(): void { - $this->client->delete('/_all'); + $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all')); - self::assertSame(404, $this->client->get('/_request/latest')->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/0')->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/first')->getStatusCode()); - self::assertSame(404, $this->client->get('/_request/last')->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/latest'))->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0'))->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/first'))->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last'))->getStatusCode()); - $this->client->get('/req/0'); - $this->client->get('/req/1'); - $this->client->get('/req/2'); - $this->client->get('/req/3'); + $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/req/0')); + $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/req/1')); + $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/req/2')); + $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/req/3')); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/last'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last')))->getRequestUri() ); self::assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->get('/_request/0'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0')))->getRequestUri() ); self::assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/1'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/1')))->getRequestUri() ); self::assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/2'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/2')))->getRequestUri() ); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/3'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/3')))->getRequestUri() ); - self::assertSame(404, $this->client->get('/_request/4')->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/4'))->getStatusCode()); self::assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->delete('/_request/last'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_request/last')))->getRequestUri() ); self::assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->delete('/_request/first'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_request/first')))->getRequestUri() ); self::assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/0'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0')))->getRequestUri() ); self::assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/1'))->getRequestUri() + $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/1')))->getRequestUri() ); - self::assertSame(404, $this->client->get('/_request/2')->getStatusCode()); + self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/2'))->getStatusCode()); } public function testErrorHandling(): void { - $this->client->delete('/_all'); + $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all')); - $response = $this->client->post('/_expectation', ['form_params' => ['matcher' => '']]); + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['matcher' => '']))) + ); self::assertSame(417, $response->getStatusCode()); - self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); + self::assertSame( + 'POST data key "matcher" must be a serialized list of closures', + (string) $response->getBody() + ); - $response = $this->client->post('/_expectation', ['form_params' => ['matcher' => ['foo']]]); + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query(['matcher' => ['foo']]) + ) + ) + ); self::assertSame(417, $response->getStatusCode()); - self::assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); + self::assertSame( + 'POST data key "matcher" must be a serialized list of closures', + (string) $response->getBody() + ); - $response = $this->client->post('/_expectation'); + $response = $this->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/_expectation')); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "response" not found in POST data', (string) $response->getBody()); - $response = $this->client->post('/_expectation', ['form_params' => ['response' => '']]); + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['response' => '']))) + ); self::assertSame(417, $response->getStatusCode()); - self::assertSame('POST data key "response" must be a serialized Symfony response', (string) $response->getBody()); + self::assertSame( + 'POST data key "response" must be a serialized Symfony response', + (string) $response->getBody() + ); - $response = $this->client->post('/_expectation', ['form_params' => ['response' => serialize(new Response()), 'limiter' => 'foo']]); + $response = $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query(['response' => serialize(new Response()), 'limiter' => 'foo']) + ) + ) + ); self::assertSame(417, $response->getStatusCode()); self::assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } public function testNewestExpectationsAreFirstEvaluated(): void { - $this->client->post( - '/_expectation', - [ - 'form_params' => $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - }, - ], - new Response('first', 200) - ), - ] - ); - self::assertSame('first', (string) $this->client->get('/')->getBody()); - - $this->client->post( - '/_expectation', - [ - 'form_params' => $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - }, - ], - new Response('second', 200) - ), - ] - ); - self::assertSame('second', (string) $this->client->get('/')->getBody()); + $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query( + $this->createExpectationParams( + [ + static function ($request) { + return $request instanceof Request; + }, + ], + new Response('first', 200) + ) + ) + ) + ) + ); + self::assertSame('first', (string) $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody()); + + $this->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/_expectation') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody( + $this->getStreamFactory()->createStream( + http_build_query( + $this->createExpectationParams( + [static function ($request) { return $request instanceof Request; }], + new Response('second', 200) + ) + ) + ) + ) + ); + self::assertSame('second', (string) $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody()); } public function testServerLogsAreNotInErrorOutput(): void { - $this->client->delete('/_all'); + $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all')); $expectedServerErrorOutput = '[404]: (null) / - No such file or directory'; diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index c17d8c0..03bccd0 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -5,7 +5,6 @@ use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\MockBuilder; use InterNations\Component\HttpMock\Server; -use PHPUnit\Framework\TestCase; use DateTime; use DateTimeZone; use InterNations\Component\HttpMock\Tests\Fixtures\Request as TestRequest; @@ -87,7 +86,10 @@ public function testCreateExpectation(): void $client = $this->server->getClient(); - self::assertSame('response body', (string) $client->post('/foo')->getBody()); + self::assertSame( + 'response body', + (string) $client->sendRequest($this->getRequestFactory()->createRequest('POST', '/foo'))->getBody() + ); self::assertNotFalse(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo')); } @@ -114,10 +116,30 @@ public function testCreateTwoExpectationsAfterEachOther(): void ->end(); $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); - self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); - self::assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); - self::assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); + self::assertSame( + 'POST 1', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/post-resource-1') + )->getBody() + ); + self::assertSame( + 'POST 2', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/post-resource-2') + )->getBody() + ); + self::assertSame( + 'POST 1', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/post-resource-1') + )->getBody() + ); + self::assertSame( + 'POST 2', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/post-resource-2') + )->getBody() + ); } public function testCreateSuccessiveExpectationsOnSameWhen(): void @@ -146,9 +168,24 @@ public function testCreateSuccessiveExpectationsOnSameWhen(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('called once', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('called twice', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('called 3 times', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame( + 'called once', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + 'called twice', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + 'called 3 times', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); } public function testCreateSuccessiveExpectationsWithAny(): void @@ -177,9 +214,9 @@ public function testCreateSuccessiveExpectationsWithAny(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('any', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('1', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody()); + self::assertSame('2', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody()); + self::assertSame('any', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody()); } public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void @@ -201,8 +238,8 @@ public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame('1', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody()); + self::assertSame('2', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody()); } public function testCreateSuccessiveExpectationsWithOnce(): void @@ -231,10 +268,35 @@ public function testCreateSuccessiveExpectationsWithOnce(): void $this->server->setUp($this->builder->flushExpectations()); - self::assertSame('1', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('2', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('twice', (string) $this->server->getClient()->post('/resource')->getBody()); - self::assertSame('Expectation not met', (string) $this->server->getClient()->post('/resource')->getBody()); + self::assertSame( + '1', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + '2', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + 'twice', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + 'twice', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); + self::assertSame( + 'Expectation not met', + (string) $this->server->getClient()->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/resource') + )->getBody() + ); } } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index cb2da91..9f5e5a4 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -1,13 +1,13 @@ end(); $this->http['firstNamedServer']->setUp(); - self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); + self::assertSame( + $path . ' body', + (string) $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', $path) + )->getBody() + ); $request = $this->http['firstNamedServer']->requests->latest(); self::assertSame('GET', $request->getMethod()); @@ -74,7 +79,7 @@ public function testSimpleRequest(string $path): void self::assertSame('GET', $request->getMethod()); self::assertSame($path, $request->getRequestUri()); - self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); + self::assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->sendRequest($this->getRequestFactory()->createRequest('GET', $path))->getBody()); $request = $this->http['firstNamedServer']->requests->shift(); self::assertSame('GET', $request->getMethod()); @@ -95,20 +100,22 @@ public function testErrorLogOutput(): void ->end(); $this->http['firstNamedServer']->setUp(); - $this->http['firstNamedServer']->client->get('/foo'); + $this->http['firstNamedServer']->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo')); // Should fail during tear down as we have an error_log() on the server side try { $this->tearDown(); self::fail('Exception expected'); } catch (\Exception $e) { - self::assertTrue(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty') !== false); + self::assertNotFalse(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty')); } } public function testFailedRequest(): void { - $response = $this->http['firstNamedServer']->client->get('/foo'); + $response = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/foo') + ); self::assertSame(404, $response->getStatusCode()); self::assertSame('No matching expectation found', (string) $response->getBody()); } @@ -121,7 +128,9 @@ public function testStopServer(): void /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt(): void { - $response = $this->http['firstNamedServer']->client->get('/'); + $response = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/') + ); self::assertSame(404, $response->getStatusCode()); } @@ -135,9 +144,13 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/'); + $firstResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/'); + $secondResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(410, $secondResponse->getStatusCode()); self::assertSame('Expectation not met', (string) $secondResponse->getBody()); @@ -149,11 +162,17 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/'); + $firstResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/'); + $secondResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/'); + $thirdResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(410, $thirdResponse->getStatusCode()); self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); @@ -165,11 +184,17 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/'); + $firstResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/'); + $secondResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/'); + $thirdResponse = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + ); self::assertSame(200, $thirdResponse->getStatusCode()); } @@ -182,7 +207,12 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http['firstNamedServer']->setUp(); - self::assertSame('CALLBACK', (string) $this->http['firstNamedServer']->client->post('/')->getBody()); + self::assertSame( + 'CALLBACK', + (string) $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + )->getBody() + ); } public function testComplexResponse(): void @@ -196,11 +226,15 @@ public function testComplexResponse(): void ->header('X-Foo', 'Bar') ->end(); $this->http['firstNamedServer']->setUp(); - $response = $this->http['firstNamedServer']->client - ->post( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] - ); + $response = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('x-client-header', 'header-value') + ->withBody( + $this->getStreamFactory()->createStream(http_build_query(['post-key' => 'post-value'])) + ) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); self::assertSame('Bar', $response->getHeaderLine('X-Foo')); @@ -218,11 +252,13 @@ public function testPutRequest(): void ->header('X-Foo', 'Bar') ->end(); $this->http['firstNamedServer']->setUp(); - $response = $this->http['firstNamedServer']->client - ->put( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['put-key' => 'put-value']] - ); + $response = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory() + ->createRequest('PUT', '/') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('x-client-header', 'header-value') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['put-key' => 'put-value']))) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); self::assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); @@ -240,11 +276,13 @@ public function testPostRequest(): void ->header('X-Foo', 'Bar') ->end(); $this->http['firstNamedServer']->setUp(); - $response = $this->http['firstNamedServer']->client - ->post( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] - ); + $response = $this->http['firstNamedServer']->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/') + ->withHeader('x-client-header', 'header-value') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['post-key' => 'post-value']))) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); self::assertSame('Bar', $response->getHeaderLine('X-Foo')); diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index f7a3baf..62a39f1 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -1,11 +1,12 @@ end(); $this->http->setUp(); - self::assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->getBody()); + self::assertSame( + '/foo body', + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/custom-base-path/foo') + )->getBody() + ); $request = $this->http->requests->latest(); self::assertSame('GET', $request->getMethod()); diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 9842bc3..b4c292b 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -2,13 +2,13 @@ namespace InterNations\Component\HttpMock\Tests\PHPUnit; use InterNations\Component\HttpMock\PHPUnit\HttpMock; -use InterNations\Component\Testing\AbstractTestCase; +use InterNations\Component\HttpMock\Tests\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use PHPUnit\Framework\TestCase; +use function http_build_query; /** @large */ -class HttpMockPHPUnitIntegrationTest extends AbstractTestCase +class HttpMockPHPUnitIntegrationTest extends TestCase { use HttpMock; @@ -52,7 +52,12 @@ public function testSimpleRequest(string $path): void ->end(); $this->http->setUp(); - self::assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); + self::assertSame( + $path . ' body', + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', $path) + )->getBody() + ); $request = $this->http->requests->latest(); self::assertSame('GET', $request->getMethod()); @@ -74,7 +79,12 @@ public function testSimpleRequest(string $path): void self::assertSame('GET', $request->getMethod()); self::assertSame($path, $request->getRequestUri()); - self::assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); + self::assertSame( + $path . ' body', + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', $path) + )->getBody() + ); $request = $this->http->requests->shift(); self::assertSame('GET', $request->getMethod()); @@ -95,7 +105,7 @@ public function testErrorLogOutput(): void ->end(); $this->http->setUp(); - $this->http->client->get('/foo'); + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo')); // Should fail during tear down as we have an error_log() on the server side try { @@ -108,7 +118,7 @@ public function testErrorLogOutput(): void public function testFailedRequest(): void { - $response = $this->http->client->get('/foo'); + $response = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo')); self::assertSame(404, $response->getStatusCode()); self::assertSame('No matching expectation found', (string) $response->getBody()); } @@ -121,7 +131,7 @@ public function testStopServer(): void /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt(): void { - $response = $this->http->client->get('/'); + $response = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo')); self::assertSame(404, $response->getStatusCode()); } @@ -135,9 +145,9 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/'); + $firstResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/'); + $secondResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(410, $secondResponse->getStatusCode()); self::assertSame('Expectation not met', (string) $secondResponse->getBody()); @@ -149,11 +159,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/'); + $firstResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/'); + $secondResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/'); + $thirdResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(410, $thirdResponse->getStatusCode()); self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); @@ -165,11 +175,11 @@ public function testLimitDurationOfAResponse(): void ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/'); + $firstResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/'); + $secondResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/'); + $thirdResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $thirdResponse->getStatusCode()); } @@ -182,7 +192,12 @@ public function testCallbackOnResponse(): void ->callback(static function(Response $response): void {$response->setContent('CALLBACK');}) ->end(); $this->http->setUp(); - self::assertSame('CALLBACK', (string) $this->http->client->post('/')->getBody()); + self::assertSame( + 'CALLBACK', + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('POST', '/') + )->getBody() + ); } public function testComplexResponse(): void @@ -196,14 +211,16 @@ public function testComplexResponse(): void ->body('BODY') ->end(); $this->http->setUp(); - $response = $this->http->client - ->post( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] - ); + $response = $this->http->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('x-client-header', 'header-value') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['post-key' => 'post-value']))) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); - self::assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + self::assertSame('Bar', $response->getHeaderLine('X-Foo')); self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key')); } @@ -218,11 +235,13 @@ public function testPutRequest(): void ->header('X-Foo', 'Bar') ->end(); $this->http->setUp(); - $response = $this->http->client - ->put( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['put-key' => 'put-value']] - ); + $response = $this->http->client->sendRequest( + $this->getRequestFactory() + ->createRequest('PUT', '/') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('x-client-header', 'header-value') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['put-key' => 'put-value']))) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); self::assertSame('Bar', $response->getHeaderLine('X-Foo')); @@ -240,11 +259,13 @@ public function testPostRequest(): void ->header('X-Foo', 'Bar') ->end(); $this->http->setUp(); - $response = $this->http->client - ->post( - '/', - ['headers' => ['x-client-header' => 'header-value'], 'form_params' => ['post-key' => 'post-value']] - ); + $response = $this->http->client->sendRequest( + $this->getRequestFactory() + ->createRequest('POST', '/') + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withHeader('x-client-header', 'header-value') + ->withBody($this->getStreamFactory()->createStream(http_build_query(['post-key' => 'post-value']))) + ); self::assertSame('BODY', (string) $response->getBody()); self::assertSame(201, $response->getStatusCode()); self::assertSame('Bar', $response->getHeaderLine('X-Foo')); @@ -262,7 +283,12 @@ public function testCountRequests(): void $this->http->setUp(); self::assertCount(0, $this->http->requests); - self::assertSame('resource body', (string) $this->http->client->get('/resource')->getBody()); + self::assertSame( + 'resource body', + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/resource') + )->getBody() + ); self::assertCount(1, $this->http->requests); } @@ -281,10 +307,18 @@ static function (Request $request) { ->end(); $this->http->setUp(); - self::assertSame('query string', (string) $this->http->client->get('/?key1=')->getBody()); - - self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->get('/')->getStatusCode()); - self::assertSame(Response::HTTP_NOT_FOUND, $this->http->client->post('/')->getStatusCode()); + self::assertSame( + 'query string', (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/?key1='))->getBody() + ); + self::assertSame( + Response::HTTP_NOT_FOUND, + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getStatusCode() + ); + self::assertSame( + Response::HTTP_NOT_FOUND, + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/'))->getStatusCode() + ); } public function testMatchRegex(): void @@ -297,8 +331,14 @@ public function testMatchRegex(): void ->end(); $this->http->setUp(); - self::assertSame('response', (string) $this->http->client->get('/')->getBody()); - self::assertSame('response', (string) $this->http->client->get('/')->getBody()); + self::assertSame( + 'response', + (string) $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody() + ); + self::assertSame( + 'response', + (string) $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody() + ); } public function testMatchQueryParams(): void @@ -318,19 +358,22 @@ public function testMatchQueryParams(): void self::assertSame( 'response', - (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->getBody() - ); + (string) $this->http->client->sendRequest( + $this->getRequestFactory()->createRequest('GET', '/?p1=&p2=v2&p4=any&p5=v5&p6=v6'))->getBody() + ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p1=&p2=v2&p3=foo')->getStatusCode() + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p1=&p2=v2&p3=foo')) + ->getStatusCode() ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p1=')->getStatusCode() + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p1='))->getStatusCode() ); self::assertSame( Response::HTTP_NOT_FOUND, - $this->http->client->get('/?p3=foo')->getStatusCode() + $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p3=foo')) + ->getStatusCode() ); } diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index 7f373d2..86e3884 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -2,14 +2,14 @@ namespace InterNations\Component\HttpMock\Tests; use GuzzleHttp\Client; -use GuzzleHttp\Psr7\Response; use InterNations\Component\HttpMock\RequestCollectionFacade; -use InterNations\Component\Testing\AbstractTestCase; use InterNations\Component\HttpMock\Tests\Fixtures\Request as TestRequest; use PHPUnit\Framework\MockObject\MockObject; +use Psr\Http\Client\ClientInterface; use Psr\Http\Message\ResponseInterface; +use function serialize; -class RequestCollectionFacadeTest extends AbstractTestCase +class RequestCollectionFacadeTest extends TestCase { /** @var Client|MockObject */ private $client; @@ -18,8 +18,8 @@ class RequestCollectionFacadeTest extends AbstractTestCase public function setUp(): void { - $this->client = $this->createMock(Client::class); - $this->facade = new RequestCollectionFacade($this->client); + $this->client = $this->createMock(ClientInterface::class); + $this->facade = new RequestCollectionFacade($this->client, $this->getRequestFactory()); } /** @return array,3:string}> */ @@ -98,7 +98,7 @@ public function testRequestResponseWithInvalidStatusCode( $this->expectException('UnexpectedValueException'); $this->expectExceptionMessage('Expected status code 200 from "' . $path . '", got 404'); - call_user_func_array([$this->facade, $method], $args); + $this->facade->{$method}(...$args); } /** @@ -117,7 +117,7 @@ public function testRequestResponseWithEmptyContentType( $this->expectException('UnexpectedValueException'); $this->expectExceptionMessage('Expected content type "text/plain" from "' . $path . '", got ""'); - call_user_func_array([$this->facade, $method], $args); + $this->facade->{$method}(...$args); } /** @@ -136,7 +136,7 @@ public function testRequestResponseWithInvalidContentType( $this->expectException('UnexpectedValueException'); $this->expectExceptionMessage('Expected content type "text/plain" from "' . $path . '", got "text/html"'); - call_user_func_array([$this->facade, $method], $args); + $this->facade->{$method}(...$args); } /** @@ -155,15 +155,15 @@ public function testRequestResponseWithDeserializationError( $this->expectException('UnexpectedValueException'); $this->expectExceptionMessage('Cannot deserialize response from "' . $path . '": "invalid response"'); - call_user_func_array([$this->facade, $method], $args); + $this->facade->{$method}(...$args); } private function mockClient(string $path, ResponseInterface $response, string $method): void { $this->client ->expects(self::once()) - ->method($method) - ->with($path) + ->method('sendRequest') + ->with($this->getRequestFactory()->createRequest($method, $path)) ->willReturn($response); } @@ -174,11 +174,10 @@ private function createSimpleResponse(): ResponseInterface $recordedRequest->setRequestUri('/foo'); $recordedRequest->setContent('RECORDED=1'); - return new Response( - '200', - ['Content-Type' => 'text/plain'], - serialize($recordedRequest) - ); + return $this->getResponseFactory() + ->createResponse() + ->withHeader('Content-Type', 'text/plain') + ->withBody($this->getStreamFactory()->createStream(serialize($recordedRequest))); } private function createComplexResponse(): ResponseInterface @@ -194,30 +193,36 @@ private function createComplexResponse(): ResponseInterface $recordedRequest->headers->set('User-Agent', 'CUSTOM UA'); - return new Response( - '200', - ['Content-Type' => 'text/plain; charset=UTF-8'], - serialize($recordedRequest) - ); + return $this->getResponseFactory() + ->createResponse() + ->withHeader('Content-Type', 'text/plain; charset=UTF-8') + ->withBody($this->getStreamFactory()->createStream(serialize($recordedRequest))); } private function createResponseWithInvalidStatusCode(): ResponseInterface { - return new Response(404); + return $this->getResponseFactory() + ->createResponse(404); } private function createResponseWithInvalidContentType(): ResponseInterface { - return new Response(200, ['Content-Type' => 'text/html']); + return $this->getResponseFactory() + ->createResponse() + ->withHeader('Content-Type', 'text/html'); } private function createResponseWithEmptyContentType(): ResponseInterface { - return new Response(200, []); + return $this->getResponseFactory() + ->createResponse(); } private function createResponseThatCannotBeDeserialized(): ResponseInterface { - return new Response(200, ['Content-Type' => 'text/plain'], 'invalid response'); + return $this->getResponseFactory() + ->createResponse() + ->withHeader('Content-Type', 'text/plain; charset=UTF-8') + ->withBody($this->getStreamFactory()->createStream('invalid response')); } } diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..91eec83 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,26 @@ + Date: Wed, 12 May 2021 16:00:48 +0200 Subject: [PATCH 27/38] JIT disabled --- src/Server.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Server.php b/src/Server.php index 599e683..8b51cc1 100644 --- a/src/Server.php +++ b/src/Server.php @@ -174,6 +174,10 @@ private static function cleanErrorOutput(string $output): string continue; } + if (strpos($line, 'JIT is incompatible with third party extensions') !== false) { + continue; + } + if (self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { continue; } From 13f2853bbdfc988d4ba469846b23220150eb232d Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 12 May 2021 16:20:02 +0200 Subject: [PATCH 28/38] Next --- src/Http/EmptyMiddleware.php | 14 ----------- src/Http/MiddlewareSupportingClient.php | 31 ++++++++++++++++++------- 2 files changed, 22 insertions(+), 23 deletions(-) delete mode 100644 src/Http/EmptyMiddleware.php diff --git a/src/Http/EmptyMiddleware.php b/src/Http/EmptyMiddleware.php deleted file mode 100644 index 283d487..0000000 --- a/src/Http/EmptyMiddleware.php +++ /dev/null @@ -1,14 +0,0 @@ -sendRequest($request); - } -} diff --git a/src/Http/MiddlewareSupportingClient.php b/src/Http/MiddlewareSupportingClient.php index 7daddf8..e838d83 100644 --- a/src/Http/MiddlewareSupportingClient.php +++ b/src/Http/MiddlewareSupportingClient.php @@ -4,28 +4,41 @@ use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use SplStack; +use function array_reduce; final class MiddlewareSupportingClient implements ClientInterface { private ClientInterface $client; - private array $middlewareStack; + /** @var SplStack|iterable */ + private SplStack $middlewareStack; public function __construct(ClientInterface $client, ClientMiddleware ...$middlewareStack) { $this->client = $client; - $this->middlewareStack = array_merge([new EmptyMiddleware()], $middlewareStack); + $this->middlewareStack = array_reduce( + $middlewareStack, + static function (SplStack $stack, ClientMiddleware $middleware) { + $stack->push($middleware); + + return $stack; + }, + new SplStack() + ); } public function sendRequest(RequestInterface $request): ResponseInterface { - $middlewareStack = $this->middlewareStack; - - $next = static function(RequestInterface $request, ClientInterface $client) use (&$middlewareStack, &$next) { - $middleware = array_pop($middlewareStack); - return $middleware->process($request, $client, $next); - }; + return self::createNext(clone $this->middlewareStack)($request, $this->client); + } - return $next($request, $this->client); + /** @param SplStack|iterable $pendingMiddlewareStack */ + private static function createNext(SplStack $pendingMiddlewareStack): callable + { + return static fn (RequestInterface $request, ClientInterface $client) => + count($pendingMiddlewareStack) > 0 + ? $pendingMiddlewareStack->pop()->process($request, $client, self::createNext($pendingMiddlewareStack)) + : $client->sendRequest($request); } } From 3243c4684cb4342d2b7af103d05b2fa42cfb7e65 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 12 May 2021 16:21:18 +0200 Subject: [PATCH 29/38] Next --- src/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.php b/src/app.php index dee8af9..2b5e0ab 100644 --- a/src/app.php +++ b/src/app.php @@ -115,7 +115,7 @@ static function (Request $currentRequest) use ($app) { $app->error( static function (Exception $e, Request $currentRequest, int $code, GetResponseForExceptionEvent $event = null) use ($app) { if ($e instanceof NotFoundHttpException) { - if (method_exists($event, 'allowCustomResponseCode')) { + if ($event && method_exists($event, 'allowCustomResponseCode')) { $event->allowCustomResponseCode(); } From 128a5c9bb5e40b510c50a823c9f945db4296b1ef Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 12 May 2021 16:25:28 +0200 Subject: [PATCH 30/38] Turn off union type hints --- phpcs.xml.dist | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 6c77b90..9f51a91 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -3,9 +3,21 @@ ./src ./tests - - - + + + + + + + + + + + + + + + From 5811f42afd72511f8639570686be4998fe5e624f Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 12 May 2021 16:27:18 +0200 Subject: [PATCH 31/38] Turn off mixed types --- phpcs.xml.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 9f51a91..6dc8d21 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -6,16 +6,19 @@ + + + From d7542771a2907acb21d744a19848364435097aff Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Mon, 17 May 2021 10:29:11 +0200 Subject: [PATCH 32/38] Replace Silex --- .gitignore | 2 +- composer.json | 13 +- phpunit.xml.dist | 1 + public/index.php | 42 +++- src/PHPUnit/HttpMockFacade.php | 6 +- src/PHPUnit/ServerManager.php | 8 +- src/RequestStorage.php | 4 + src/ServerApplication.php | 267 ++++++++++++++++++++++++++ src/{Server.php => ServerProcess.php} | 12 +- src/app.php | 232 ---------------------- state/.gitkeep | 0 tests/AppIntegrationTest.php | 9 +- tests/MockBuilderIntegrationTest.php | 6 +- 13 files changed, 343 insertions(+), 259 deletions(-) create mode 100644 src/ServerApplication.php rename src/{Server.php => ServerProcess.php} (95%) delete mode 100644 src/app.php delete mode 100644 state/.gitkeep diff --git a/.gitignore b/.gitignore index 63ae91d..094f441 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ vendor/ composer.lock .idea/ -state/*-* +var/ build/* phpunit.xml .phpunit.result.cache diff --git a/composer.json b/composer.json index e5a0bce..e2ed91e 100644 --- a/composer.json +++ b/composer.json @@ -14,8 +14,7 @@ ], "require": { "php": "~7.4|~8.0", - "silex/silex": "~2.0", - "symfony/process": "~3|~4|~5", + "symfony/process": "~4|~5", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0", "opis/closure": "^3.6", @@ -23,8 +22,14 @@ "psr/http-factory": "^1.0", "guzzlehttp/psr7": "^1.8", "http-interop/http-factory-guzzle": "^1.0", - "php-http/discovery": "^1.13" - }, + "php-http/discovery": "^1.13", + "symfony/config": "~4|~5", + "symfony/http-kernel": "~4|~5", + "symfony/http-foundation": "~4|~5", + "symfony/routing": "~4|~5", + "symfony/dependency-injection": "~4|~5", + "symfony/framework-bundle": "~4|~5" + }, "require-dev": { "internations/testing-component": "1.0.1", "phpunit/phpunit": "^9" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8298e09..07a6982 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -31,5 +31,6 @@ + diff --git a/public/index.php b/public/index.php index d9d901e..037b674 100644 --- a/public/index.php +++ b/public/index.php @@ -1,8 +1,46 @@ run(); +$autoloadFiles = [ + __DIR__ . '/../vendor/autoload.php', + __DIR__ . '/../../../autoload.php', +]; + +$autoloaderFound = false; + +foreach ($autoloadFiles as $autoloadFile) { + if (file_exists($autoloadFile)) { + require_once $autoloadFile; + $autoloaderFound = true; + break; + } +} + +if (!$autoloaderFound) { + throw new RuntimeException( + sprintf('Could not locate autoloader file. Tried "%s"', implode('", "', $autoloadFiles)) + ); +} + +Request::setFactory(static fn (...$args) => new SerializableRequest(...$args)); +$app = new ServerApplication('prod', getenv('HTTP_MOCK_TESTSUITE') === 'true'); +$request = Request::createFromGlobals(); +$response = $app->handle($request); +$response->send(); +$app->terminate($request, $response); diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index c42e2f0..6a9ce01 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -7,12 +7,12 @@ use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\MockBuilder; use InterNations\Component\HttpMock\RequestCollectionFacade; -use InterNations\Component\HttpMock\Server; +use InterNations\Component\HttpMock\ServerProcess; use Psr\Http\Client\ClientInterface; use RuntimeException; /** - * @property-read Server $server The HTTP mock server that is currently running + * @property-read ServerProcess $server The HTTP mock server that is currently running * @property-read MatcherFactory $matches An instance of the matcher factory * @property-read MockBuilder $mock An instance of the mock builder * @property-read RequestCollectionFacade $requests Convenient access to recorded requests @@ -27,7 +27,7 @@ class HttpMockFacade public function __construct(int $port, string $host, ?string $basePath = null) { - $server = new Server($port, $host); + $server = new ServerProcess($port, $host); $server->start(); $this->services['server'] = $server; $this->basePath = $basePath; diff --git a/src/PHPUnit/ServerManager.php b/src/PHPUnit/ServerManager.php index a6005a3..e608822 100644 --- a/src/PHPUnit/ServerManager.php +++ b/src/PHPUnit/ServerManager.php @@ -1,14 +1,14 @@ */ + /** @var SplObjectStorage|iterable */ private SplObjectStorage $servers; private static ?self $instance = null; @@ -18,12 +18,12 @@ public static function getInstance(): self return self::$instance ?: (self::$instance = new self()); } - public function add(Server $server): void + public function add(ServerProcess $server): void { $this->servers->attach($server); } - public function remove(Server $server): void + public function remove(ServerProcess $server): void { $this->servers->detach($server); } diff --git a/src/RequestStorage.php b/src/RequestStorage.php index b6dbe56..dcbd335 100644 --- a/src/RequestStorage.php +++ b/src/RequestStorage.php @@ -11,6 +11,10 @@ class RequestStorage public function __construct(int $pid, string $directory) { + if (!is_dir($directory)) { + mkdir($directory); + } + $this->pid = $pid; $this->directory = $directory; } diff --git a/src/ServerApplication.php b/src/ServerApplication.php new file mode 100644 index 0000000..8c76bc8 --- /dev/null +++ b/src/ServerApplication.php @@ -0,0 +1,267 @@ + */ + public function registerBundles(): array + { + return [new FrameworkBundle()]; + } + + public function configureContainer(ContainerConfigurator $container): void + { + $container->extension('framework', ['secret' => base64_encode(random_bytes(8))]); + + $container->services() + ->set(RequestStorage::class) + ->args([getmypid(), $this->getCacheDir() . '/state/']); + } + + public function configureRoutes(RoutingConfigurator $routes): void + { + $routes + ->add('me', '/_me') + ->controller([$this, 'meAction']) + ->methods(['GET']) + + ->add('reset_all', '/_all') + ->controller([$this, 'resetAll']) + ->methods(['DELETE']) + + ->add('request_delete_all', '/_request') + ->controller([$this, 'deleteRequests']) + ->methods(['DELETE']) + + ->add('request_by_position_get', '/_request/{position}') + ->controller([$this, 'getRequestByPosition']) + ->methods(['GET']) + ->requirements(['position' => 'first|last'])# + + ->add('request_by_position_delete', '/_request/{position}') + ->controller([$this, 'deleteRequestByPosition']) + ->methods(['DELETE']) + ->requirements(['position' => 'first|last']) + + ->add('request_by_index_get', '/_request/{index}') + ->controller([$this, 'getRequestByIndex']) + ->methods(['GET']) + ->requirements(['index' => '\d+']) + + ->add('request_count', '/_request/count') + ->controller([$this, 'countRequests']) + ->methods(['GET']) + + ->add('expectations_delete_all', '/_expectation') + ->controller([$this, 'deleteExpectations']) + ->methods(['DELETE']) + + ->add('expectations_post', '/_expectation') + ->controller([$this, 'postExpectations']) + ->methods(['POST']) + + ->add('record', '{path}') + ->controller([$this, 'record']) + ->requirements(['path' => '.*']) + ; + } + + public function meAction(): Response + { + return new Response('O RLY?', Response::HTTP_I_AM_A_TEAPOT, ['Content-Type' => 'text/plain']); + } + + public function resetAll(Request $currentRequest, RequestStorage $requestStorage): Response + { + $requestStorage->store($currentRequest, 'requests', []); + $requestStorage->store($currentRequest, 'expectations', []); + + return new Response('', Response::HTTP_OK); + } + + public function deleteRequests(Request $currentRequest, RequestStorage $requestStorage): Response + { + $requestStorage->store($currentRequest, 'requests', []); + + return new Response('', Response::HTTP_OK); + } + + public function getRequestByIndex( + int $index, + Request $currentRequest, + RequestStorage $requestStorage + + ): Response + { + $requests = $requestStorage->read($currentRequest, 'requests'); + + if (!isset($requests[$index])) { + return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND); + } + + return new Response($requests[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); + } + + public function getRequestByPosition( + string $position, + Request $currentRequest, + RequestStorage $requestStorage + ): Response + { + $requestData = $requestStorage->read($currentRequest, 'requests'); + $fn = 'array_' . ($position === 'last' ? 'pop': 'shift'); + $request = $fn($requestData); + + if (!$request) { + return new Response($position . ' not available', Response::HTTP_NOT_FOUND); + } + + return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + } + + public function deleteRequestByPosition( + string $position, + Request $currentRequest, + RequestStorage $requestStorage + ): Response + { + $requests = $requestStorage->read($currentRequest, 'requests'); + $fn = 'array_' . ($position === 'last' ? 'pop' : 'shift'); + $request = $fn($requests); + $requestStorage->store($currentRequest, 'requests', $requests); + + if (!$request) { + return new Response($position . ' not possible', Response::HTTP_NOT_FOUND); + } + + return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + } + + public function countRequests(Request $currentRequest, RequestStorage $requestStorage): Response + { + return new Response( + count($requestStorage->read($currentRequest, 'requests')), + Response::HTTP_OK, + ['Content-Type' => 'text/plain'] + ); + } + + public function postExpectations(Request $currentRequest, RequestStorage $requestStorage): Response + { + $matcher = []; + + if ($currentRequest->request->has('matcher')) { + $matcherParameter = $currentRequest->request->get('matcher'); + if (!is_string($matcherParameter)) { + return new Response( + 'POST data key "matcher" must be a serialized list of closures', + Response::HTTP_EXPECTATION_FAILED + ); + } + + $matcher = Util::silentDeserialize($matcherParameter); + $validator = static function ($closure) { + return is_callable($closure); + }; + + if (!is_array($matcher) || count(array_filter($matcher, $validator)) !== count($matcher)) { + return new Response( + 'POST data key "matcher" must be a serialized list of closures', + Response::HTTP_EXPECTATION_FAILED + ); + } + } + + if (!$currentRequest->request->has('response')) { + return new Response('POST data key "response" not found in POST data', Response::HTTP_EXPECTATION_FAILED); + } + + $response = Util::silentDeserialize($currentRequest->request->get('response')); + + if (!$response instanceof Response) { + return new Response( + 'POST data key "response" must be a serialized Symfony response', + Response::HTTP_EXPECTATION_FAILED + ); + } + + $limiter = null; + + if ($currentRequest->request->has('limiter')) { + $limiter = Util::silentDeserialize($currentRequest->request->get('limiter')); + + if (!is_callable($limiter)) { + return new Response( + 'POST data key "limiter" must be a serialized closure', + Response::HTTP_EXPECTATION_FAILED + ); + } + } + + $requestStorage->prepend( + $currentRequest, + 'expectations', + ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0] + ); + + return new Response('', Response::HTTP_CREATED); + } + + public function record(Request $currentRequest, RequestStorage $requestStorage): Response + { + $requestStorage->append($currentRequest, 'requests', serialize($currentRequest)); + + $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); + + $expectations = $requestStorage->read($currentRequest, 'expectations'); + + foreach ($expectations as $pos => $expectation) { + foreach ($expectation['matcher'] as $matcher) { + if (!$matcher($currentRequest)) { + continue 2; + } + } + + $applicable = !isset($expectation['limiter']) || $expectation['limiter']($expectation['runs']); + + ++$expectations[$pos]['runs']; + $requestStorage->store($currentRequest, 'expectations', $expectations); + + if (!$applicable) { + $notFoundResponse = new Response('Expectation not met', Response::HTTP_GONE); + continue; + } + + return $expectation['response']; + } + + return $notFoundResponse; + } + + public function deleteExpectations(Request $currentRequest, RequestStorage $requestStorage): Response + { + $requestStorage->clear($currentRequest, 'expectations'); + + return new Response('', Response::HTTP_OK); + + } +} diff --git a/src/Server.php b/src/ServerProcess.php similarity index 95% rename from src/Server.php rename to src/ServerProcess.php index 8b51cc1..c53b913 100644 --- a/src/Server.php +++ b/src/ServerProcess.php @@ -1,7 +1,6 @@ getenv('HTTP_MOCK_TESTSUITE')]); $this->setTimeout(null); } @@ -178,6 +176,10 @@ private static function cleanErrorOutput(string $output): string continue; } + if (strpos($line, '[info]') !== false) { + continue; + } + if (self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { continue; } diff --git a/src/app.php b/src/app.php deleted file mode 100644 index 2b5e0ab..0000000 --- a/src/app.php +++ /dev/null @@ -1,232 +0,0 @@ - new SerializableRequest(...$args)); - -$app = new Application(); -$app['storage'] = new RequestStorage(getmypid(), __DIR__ . '/../state/'); - -$app->delete( - '/_expectation', - static function (Request $currentRequest) use ($app) { - $app['storage']->clear($currentRequest, 'expectations'); - - return new Response('', Response::HTTP_OK); - } -); - -$app->post( - '/_expectation', - static function (Request $currentRequest) use ($app) { - - $matcher = []; - - if ($currentRequest->request->has('matcher')) { - $matcherParameter = $currentRequest->request->get('matcher'); - if (!is_string($matcherParameter)) { - return new Response( - 'POST data key "matcher" must be a serialized list of closures', - Response::HTTP_EXPECTATION_FAILED - ); - } - - $matcher = Util::silentDeserialize($matcherParameter); - $validator = static function ($closure) { - return is_callable($closure); - }; - - if (!is_array($matcher) || count(array_filter($matcher, $validator)) !== count($matcher)) { - return new Response( - 'POST data key "matcher" must be a serialized list of closures', - Response::HTTP_EXPECTATION_FAILED - ); - } - } - - if (!$currentRequest->request->has('response')) { - return new Response('POST data key "response" not found in POST data', Response::HTTP_EXPECTATION_FAILED); - } - - $response = Util::silentDeserialize($currentRequest->request->get('response')); - - if (!$response instanceof Response) { - return new Response( - 'POST data key "response" must be a serialized Symfony response', - Response::HTTP_EXPECTATION_FAILED - ); - } - - $limiter = null; - - if ($currentRequest->request->has('limiter')) { - $limiter = Util::silentDeserialize($currentRequest->request->get('limiter')); - - if (!is_callable($limiter)) { - return new Response( - 'POST data key "limiter" must be a serialized closure', - Response::HTTP_EXPECTATION_FAILED - ); - } - } - - // Fix issue with silex default error handling - $response->headers->set('X-Status-Code', $response->getStatusCode()); - - $app['storage']->prepend( - $currentRequest, - 'expectations', - ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0] - ); - - return new Response('', Response::HTTP_CREATED); - } -); - -$app->error( - static function (Exception $e, Request $currentRequest, int $code, GetResponseForExceptionEvent $event = null) use ($app) { - if ($e instanceof NotFoundHttpException) { - if ($event && method_exists($event, 'allowCustomResponseCode')) { - $event->allowCustomResponseCode(); - } - - $app['storage']->append($currentRequest, 'requests', serialize($currentRequest)); - - $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); - - $expectations = $app['storage']->read($currentRequest, 'expectations'); - - foreach ($expectations as $pos => $expectation) { - foreach ($expectation['matcher'] as $matcher) { - if (!$matcher($currentRequest)) { - continue 2; - } - } - - $applicable = !isset($expectation['limiter']) || $expectation['limiter']($expectation['runs']); - - ++$expectations[$pos]['runs']; - $app['storage']->store($currentRequest, 'expectations', $expectations); - - if (!$applicable) { - $notFoundResponse = new Response('Expectation not met', Response::HTTP_GONE); - continue; - } - - return $expectation['response']; - } - - return $notFoundResponse; - } - - return new Response('Server error: ' . $e->getMessage(), $code); - } -); - -$app->get( - '/_request/count', - static function (Request $currentRequest) use ($app) { - return count($app['storage']->read($currentRequest, 'requests')); - } -); - -$app->get( - '/_request/{index}', - static function (Request $currentRequest, $index) use ($app) { - $requests = $app['storage']->read($currentRequest, 'requests'); - - if (!isset($requests[$index])) { - return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND); - } - - return new Response($requests[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); - } -)->assert('index', '\d+'); - -$app->delete( - '/_request/{action}', - static function (Request $currentRequest, $action) use ($app) { - $requests = $app['storage']->read($currentRequest, 'requests'); - $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); - $request = $fn($requests); - $app['storage']->store($currentRequest, 'requests', $requests); - - if (!$request) { - return new Response($action . ' not possible', Response::HTTP_NOT_FOUND); - } - - return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); - } -)->assert('index', '(last|first)'); - -$app->get( - '/_request/{action}', - static function (Request $currentRequest, $action) use ($app) { - $requestData = $app['storage']->read($currentRequest, 'requests'); - $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); - $request = $fn($requestData); - - if (!$request) { - return new Response($action . ' not available', Response::HTTP_NOT_FOUND); - } - - return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); - } -)->assert('index', '(last|first)'); - -$app->delete( - '/_request', - static function (Request $currentRequest) use ($app) { - $app['storage']->store($currentRequest, 'requests', []); - - return new Response('', Response::HTTP_OK); - } -); - -$app->delete( - '/_all', - static function (Request $currentRequest) use ($app) { - $app['storage']->store($currentRequest, 'requests', []); - $app['storage']->store($currentRequest, 'expectations', []); - - return new Response('', Response::HTTP_OK); - } -); - -$app->get( - '/_me', - static function () { - return new Response('O RLY?', Response::HTTP_I_AM_A_TEAPOT, ['Content-Type' => 'text/plain']); - } -); - -return $app; diff --git a/state/.gitkeep b/state/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index 35399eb..ca0470a 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -3,7 +3,7 @@ use Closure; use Guzzle\Http\Message\RequestInterface; -use InterNations\Component\HttpMock\Server; +use InterNations\Component\HttpMock\ServerProcess; use InterNations\Component\HttpMock\Util; use Guzzle\Http\Message\RequestFactory; use Opis\Closure\SerializableClosure; @@ -19,13 +19,13 @@ */ class AppIntegrationTest extends TestCase { - private static Server $server1; + private static ServerProcess $server1; private ClientInterface $client; public static function setUpBeforeClass(): void { - static::$server1 = new Server(HTTP_MOCK_PORT, HTTP_MOCK_HOST); + static::$server1 = new ServerProcess(HTTP_MOCK_PORT, HTTP_MOCK_HOST); static::$server1->start(); } @@ -81,7 +81,7 @@ static function ($request) { self::assertSame(200, $response->getStatusCode()); self::assertSame('fake body', (string) $response->getBody()); - $response = $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/latest')); + $response = $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last')); $request = $this->parseRequestFromResponse($response); self::assertSame('1', $request->headers->get('X-Special')); @@ -92,7 +92,6 @@ public function testRecording(): void { $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all')); - self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/latest'))->getStatusCode()); self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0'))->getStatusCode()); self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/first'))->getStatusCode()); self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last'))->getStatusCode()); diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 03bccd0..226e9da 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -4,7 +4,7 @@ use InterNations\Component\HttpMock\Matcher\ExtractorFactory; use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\MockBuilder; -use InterNations\Component\HttpMock\Server; +use InterNations\Component\HttpMock\ServerProcess; use DateTime; use DateTimeZone; use InterNations\Component\HttpMock\Tests\Fixtures\Request as TestRequest; @@ -20,13 +20,13 @@ class MockBuilderIntegrationTest extends TestCase private MatcherFactory $matches; - private Server $server; + private ServerProcess $server; public function setUp(): void { $this->matches = new MatcherFactory(); $this->builder = new MockBuilder($this->matches, new ExtractorFactory()); - $this->server = new Server(HTTP_MOCK_PORT, HTTP_MOCK_HOST); + $this->server = new ServerProcess(HTTP_MOCK_PORT, HTTP_MOCK_HOST); $this->server->start(); $this->server->clean(); } From edfe137658cb6720f0f27bdc2e9efab97415475c Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 18 May 2021 11:12:42 +0200 Subject: [PATCH 33/38] Refactor storage --- src/FileBasedStorage.php | 98 +++++++++++++ src/RequestCollectionFacade.php | 2 - src/RequestStorage.php | 76 ++-------- src/ServerApplication.php | 132 +++++++----------- src/ServerExpectation.php | 54 +++++++ tests/MockBuilderIntegrationTest.php | 2 +- .../HttpMockMultiPHPUnitIntegrationTest.php | 8 +- .../HttpMockPHPUnitIntegrationTest.php | 8 +- 8 files changed, 227 insertions(+), 153 deletions(-) create mode 100644 src/FileBasedStorage.php create mode 100644 src/ServerExpectation.php diff --git a/src/FileBasedStorage.php b/src/FileBasedStorage.php new file mode 100644 index 0000000..32c7113 --- /dev/null +++ b/src/FileBasedStorage.php @@ -0,0 +1,98 @@ +pid = $pid; + $this->directory = $directory; + $this->requestStack = $requestStack; + } + + /** @param list $requests */ + public function storeRequests(array $requests): void + { + file_put_contents($this->getFileName(self::NAMESPACE_REQUESTS), serialize($requests)); + } + + public function appendRequest(Request $request): void + { + $list = $this->read(self::NAMESPACE_REQUESTS); + $list[] = $request; + $this->store(self::NAMESPACE_REQUESTS, $list); + } + + /** @return list */ + public function readExpectations(): array + { + return $this->read(self::NAMESPACE_EXPECTATIONS); + } + + /** @return list */ + public function readRequests(): array + { + return $this->read(self::NAMESPACE_REQUESTS); + } + + /** @param list $expectations */ + public function storeExpectations(array $expectations): void + { + $this->store(self::NAMESPACE_EXPECTATIONS, $expectations); + } + + public function prependExpectation(ServerExpectation $expectation): void + { + $list = $this->read(self::NAMESPACE_EXPECTATIONS); + array_unshift($list, $expectation); + $this->store(self::NAMESPACE_EXPECTATIONS, $list); + } + + /** @param array|array $data */ + private function store(string $name, array $data): void + { + file_put_contents($this->getFileName($name), serialize($data)); + } + + /** @return array|array */ + private function read(string $name): array + { + $fileName = $this->getFileName($name); + + if (!file_exists($fileName)) { + return []; + } + + return Util::deserialize(file_get_contents($fileName)); + } + + private function getFileName(string $namespace): string + { + return sprintf( + '%s/%d-%s-%d.data', + $this->directory, + $this->pid, + $namespace, + $this->requestStack->getMasterRequest()->server->get('SERVER_PORT') + ); + } +} diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index 43f422c..397a8b2 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -2,11 +2,9 @@ namespace InterNations\Component\HttpMock; use Countable; -use GuzzleHttp\Client; use GuzzleHttp\Psr7\Response; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; -use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Request; use UnexpectedValueException; diff --git a/src/RequestStorage.php b/src/RequestStorage.php index dcbd335..2e99813 100644 --- a/src/RequestStorage.php +++ b/src/RequestStorage.php @@ -3,69 +3,17 @@ use Symfony\Component\HttpFoundation\Request; -class RequestStorage +interface RequestStorage { - private int $pid; - - private string $directory; - - public function __construct(int $pid, string $directory) - { - if (!is_dir($directory)) { - mkdir($directory); - } - - $this->pid = $pid; - $this->directory = $directory; - } - - /** @param array|array $data */ - public function store(Request $request, string $name, array $data): void - { - file_put_contents($this->getFileName($request, $name), serialize($data)); - } - - /** @return array|array */ - public function read(Request $request, string $name): array - { - $fileName = $this->getFileName($request, $name); - - if (!file_exists($fileName)) { - return []; - } - - return Util::deserialize(file_get_contents($fileName)); - } - - /** @param Request|Expectation $data */ - public function append(Request $request, string $name, $data): void - { - $list = $this->read($request, $name); - $list[] = $data; - $this->store($request, $name, $list); - } - - /** @param Request|Expectation $data */ - public function prepend(Request $request, string $name, $data): void - { - $list = $this->read($request, $name); - array_unshift($list, $data); - $this->store($request, $name, $list); - } - - private function getFileName(Request $request, string $name): string - { - return $this->directory . $this->pid . '-' . $name . '-' . $request->server->get('SERVER_PORT'); - } - - public function clear(Request $request, string $name): void - { - $fileName = $this->getFileName($request, $name); - - if (!file_exists($fileName)) { - return; - } - - unlink($fileName); - } + /** @param list $expectations */ + public function storeExpectations(array $expectations): void; + /** @return array */ + public function readExpectations(): array; + public function prependExpectation(ServerExpectation $expectation): void; + + /** @param list $requests */ + public function storeRequests(array $requests): void; + /** @return array */ + public function readRequests(): array; + public function appendRequest(Request $request): void; } diff --git a/src/ServerApplication.php b/src/ServerApplication.php index 8c76bc8..5f6605a 100644 --- a/src/ServerApplication.php +++ b/src/ServerApplication.php @@ -32,8 +32,10 @@ public function configureContainer(ContainerConfigurator $container): void { $container->extension('framework', ['secret' => base64_encode(random_bytes(8))]); - $container->services() - ->set(RequestStorage::class) + $container + ->services() + ->set(RequestStorage::class, FileBasedStorage::class) + ->autowire() ->args([getmypid(), $this->getCacheDir() . '/state/']); } @@ -45,7 +47,7 @@ public function configureRoutes(RoutingConfigurator $routes): void ->methods(['GET']) ->add('reset_all', '/_all') - ->controller([$this, 'resetAll']) + ->controller([$this, 'deleteAll']) ->methods(['DELETE']) ->add('request_delete_all', '/_request') @@ -87,82 +89,65 @@ public function configureRoutes(RoutingConfigurator $routes): void public function meAction(): Response { - return new Response('O RLY?', Response::HTTP_I_AM_A_TEAPOT, ['Content-Type' => 'text/plain']); + return self::createResponse(Response::HTTP_I_AM_A_TEAPOT, 'O RLY?'); } - public function resetAll(Request $currentRequest, RequestStorage $requestStorage): Response + public function deleteAll(RequestStorage $requestStorage): Response { - $requestStorage->store($currentRequest, 'requests', []); - $requestStorage->store($currentRequest, 'expectations', []); + $requestStorage->storeRequests([]); + $requestStorage->storeExpectations([]); - return new Response('', Response::HTTP_OK); + return self::createResponse(Response::HTTP_OK); } - public function deleteRequests(Request $currentRequest, RequestStorage $requestStorage): Response + public function deleteRequests(RequestStorage $requestStorage): Response { - $requestStorage->store($currentRequest, 'requests', []); + $requestStorage->storeRequests([]); - return new Response('', Response::HTTP_OK); + return self::createResponse(Response::HTTP_OK); } - public function getRequestByIndex( - int $index, - Request $currentRequest, - RequestStorage $requestStorage - - ): Response + public function getRequestByIndex(int $index, RequestStorage $requestStorage): Response { - $requests = $requestStorage->read($currentRequest, 'requests'); + $requests = $requestStorage->readRequests(); if (!isset($requests[$index])) { - return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND); + return self::createResponse(Response::HTTP_NOT_FOUND, 'Index ' . $index . ' not found'); } - return new Response($requests[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return self::createResponse(Response::HTTP_OK, serialize($requests[$index])); } - public function getRequestByPosition( - string $position, - Request $currentRequest, - RequestStorage $requestStorage - ): Response + public function getRequestByPosition(string $position, RequestStorage $requestStorage): Response { - $requestData = $requestStorage->read($currentRequest, 'requests'); + $requestData = $requestStorage->readRequests(); $fn = 'array_' . ($position === 'last' ? 'pop': 'shift'); $request = $fn($requestData); if (!$request) { - return new Response($position . ' not available', Response::HTTP_NOT_FOUND); + return self::createResponse(Response::HTTP_NOT_FOUND, $position . ' not available'); } - return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return self::createResponse(Response::HTTP_OK, serialize($request)); } - public function deleteRequestByPosition( - string $position, - Request $currentRequest, - RequestStorage $requestStorage - ): Response + public function deleteRequestByPosition(string $position, RequestStorage $requestStorage): Response { - $requests = $requestStorage->read($currentRequest, 'requests'); + $requests = $requestStorage->readRequests(); $fn = 'array_' . ($position === 'last' ? 'pop' : 'shift'); $request = $fn($requests); - $requestStorage->store($currentRequest, 'requests', $requests); + $requestStorage->storeRequests($requests); if (!$request) { - return new Response($position . ' not possible', Response::HTTP_NOT_FOUND); + return self::createResponse(Response::HTTP_NOT_FOUND, $position . ' not possible'); } - return new Response($request, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return self::createResponse(Response::HTTP_OK, serialize($request)); } - public function countRequests(Request $currentRequest, RequestStorage $requestStorage): Response + public function countRequests(RequestStorage $requestStorage): Response { - return new Response( - count($requestStorage->read($currentRequest, 'requests')), - Response::HTTP_OK, - ['Content-Type' => 'text/plain'] - ); + return self::createResponse(Response::HTTP_OK, count($requestStorage->readRequests())); } public function postExpectations(Request $currentRequest, RequestStorage $requestStorage): Response @@ -172,9 +157,9 @@ public function postExpectations(Request $currentRequest, RequestStorage $reques if ($currentRequest->request->has('matcher')) { $matcherParameter = $currentRequest->request->get('matcher'); if (!is_string($matcherParameter)) { - return new Response( - 'POST data key "matcher" must be a serialized list of closures', - Response::HTTP_EXPECTATION_FAILED + return self::createResponse( + Response::HTTP_EXPECTATION_FAILED, + 'POST data key "matcher" must be a serialized list of closures' ); } @@ -184,9 +169,9 @@ public function postExpectations(Request $currentRequest, RequestStorage $reques }; if (!is_array($matcher) || count(array_filter($matcher, $validator)) !== count($matcher)) { - return new Response( - 'POST data key "matcher" must be a serialized list of closures', - Response::HTTP_EXPECTATION_FAILED + return self::createResponse( + Response::HTTP_EXPECTATION_FAILED, + 'POST data key "matcher" must be a serialized list of closures' ); } } @@ -217,51 +202,42 @@ public function postExpectations(Request $currentRequest, RequestStorage $reques } } - $requestStorage->prepend( - $currentRequest, - 'expectations', - ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0] - ); + $requestStorage->prependExpectation(new ServerExpectation($matcher, $response, $limiter, 0)); - return new Response('', Response::HTTP_CREATED); + return self::createResponse(Response::HTTP_CREATED); } public function record(Request $currentRequest, RequestStorage $requestStorage): Response { - $requestStorage->append($currentRequest, 'requests', serialize($currentRequest)); - - $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); + $requestStorage->appendRequest($currentRequest); + $expectations = $requestStorage->readExpectations(); - $expectations = $requestStorage->read($currentRequest, 'expectations'); + try { + foreach ($expectations as $expectation) { + $response = $expectation->matchRequest($currentRequest); - foreach ($expectations as $pos => $expectation) { - foreach ($expectation['matcher'] as $matcher) { - if (!$matcher($currentRequest)) { - continue 2; + if (!$response) { + continue; } - } - - $applicable = !isset($expectation['limiter']) || $expectation['limiter']($expectation['runs']); - - ++$expectations[$pos]['runs']; - $requestStorage->store($currentRequest, 'expectations', $expectations); - if (!$applicable) { - $notFoundResponse = new Response('Expectation not met', Response::HTTP_GONE); - continue; + return $response; } - return $expectation['response']; + return self::createResponse(Response::HTTP_NOT_FOUND, 'No matching expectation found'); + } finally { + $requestStorage->storeExpectations($expectations); } - - return $notFoundResponse; } - public function deleteExpectations(Request $currentRequest, RequestStorage $requestStorage): Response + public function deleteExpectations(RequestStorage $requestStorage): Response { - $requestStorage->clear($currentRequest, 'expectations'); + $requestStorage->storeExpectations([]); - return new Response('', Response::HTTP_OK); + return self::createResponse(Response::HTTP_OK); + } + private static function createResponse(int $statusCode, string $body = ''): Response + { + return new Response($body, $statusCode, ['Content-Type' => 'text/plain']); } } diff --git a/src/ServerExpectation.php b/src/ServerExpectation.php new file mode 100644 index 0000000..14d53c0 --- /dev/null +++ b/src/ServerExpectation.php @@ -0,0 +1,54 @@ + */ + private array $matchers; + private Response $response; + /** @var callable|null */ + private $limiter; + private int $runs; + + /** @param list $matchers */ + public function __construct(array $matchers, Response $response, ?callable $limiter, int $runs) + { + $this->matchers = $matchers; + $this->response = $response; + $this->limiter = $limiter; + $this->runs = $runs; + } + + public function matchRequest(Request $currentRequest): ?Response + { + if (!$this->matches($currentRequest)) { + return null; + } + + try { + return $this->isApplicable() ? $this->response : null; + } finally { + $this->runs++; + } + } + + private function matches(Request $currentRequest): bool + { + foreach ($this->matchers as $matcher) { + if (!$matcher($currentRequest)) { + return false; + } + } + + return true; + } + + private function isApplicable(): bool + { + $limiter = $this->limiter; + return $limiter === null || $limiter($this->runs); + } +} diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 226e9da..5f81b48 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -293,7 +293,7 @@ public function testCreateSuccessiveExpectationsWithOnce(): void )->getBody() ); self::assertSame( - 'Expectation not met', + 'No matching expectation found', (string) $this->server->getClient()->sendRequest( $this->getRequestFactory()->createRequest('POST', '/resource') )->getBody() diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index 9f5e5a4..9df4c66 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -151,8 +151,8 @@ public function testLimitDurationOfAResponse(): void $secondResponse = $this->http['firstNamedServer']->client->sendRequest( $this->getRequestFactory()->createRequest('POST', '/') ); - self::assertSame(410, $secondResponse->getStatusCode()); - self::assertSame('Expectation not met', (string) $secondResponse->getBody()); + self::assertSame(404, $secondResponse->getStatusCode()); + self::assertSame('No matching expectation found', (string) $secondResponse->getBody()); $this->http['firstNamedServer']->mock ->exactly(2) @@ -173,8 +173,8 @@ public function testLimitDurationOfAResponse(): void $thirdResponse = $this->http['firstNamedServer']->client->sendRequest( $this->getRequestFactory()->createRequest('POST', '/') ); - self::assertSame(410, $thirdResponse->getStatusCode()); - self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); + self::assertSame(404, $thirdResponse->getStatusCode()); + self::assertSame('No matching expectation found', (string) $thirdResponse->getBody()); $this->http['firstNamedServer']->mock ->any() diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index b4c292b..f8b5db9 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -148,8 +148,8 @@ public function testLimitDurationOfAResponse(): void $firstResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $firstResponse->getStatusCode()); $secondResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); - self::assertSame(410, $secondResponse->getStatusCode()); - self::assertSame('Expectation not met', (string) $secondResponse->getBody()); + self::assertSame(404, $secondResponse->getStatusCode()); + self::assertSame('No matching expectation found', (string) $secondResponse->getBody()); $this->http->mock ->exactly(2) @@ -164,8 +164,8 @@ public function testLimitDurationOfAResponse(): void $secondResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); self::assertSame(200, $secondResponse->getStatusCode()); $thirdResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/')); - self::assertSame(410, $thirdResponse->getStatusCode()); - self::assertSame('Expectation not met', (string) $thirdResponse->getBody()); + self::assertSame(404, $thirdResponse->getStatusCode()); + self::assertSame('No matching expectation found', (string) $thirdResponse->getBody()); $this->http->mock ->any() From 87170422d5e6fa84891cec10155f7d84e59a4500 Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 18 May 2021 11:17:14 +0200 Subject: [PATCH 34/38] Unused use statements --- phpcs.xml.dist | 6 +++++- src/PHPUnit/HttpMockFacade.php | 1 - tests/AppIntegrationTest.php | 2 -- tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php | 1 - tests/RequestCollectionFacadeTest.php | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 6dc8d21..2c488fe 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -39,7 +39,11 @@ - + + + + + diff --git a/src/PHPUnit/HttpMockFacade.php b/src/PHPUnit/HttpMockFacade.php index 6a9ce01..347bc86 100644 --- a/src/PHPUnit/HttpMockFacade.php +++ b/src/PHPUnit/HttpMockFacade.php @@ -1,7 +1,6 @@ Date: Tue, 18 May 2021 11:21:54 +0200 Subject: [PATCH 35/38] Next --- phpcs.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 2c488fe..78a1d66 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -71,7 +71,6 @@ - From fbd074842a935bbf49263bacb8a31092dd9dd66f Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 18 May 2021 12:29:00 +0200 Subject: [PATCH 36/38] Introduce dependency tracking --- .github/workflows/test.yaml | 4 + .gitignore | 1 + composer.json | 7 +- depfile.yaml | 114 +++++++++++++++++++++++++ public/index.php | 1 + src/Expectation.php | 1 + src/RequestCollectionFacade.php | 6 +- src/{ => Response}/ResponseBuilder.php | 4 +- src/{ => Server}/FileBasedStorage.php | 3 +- src/{ => Server}/RequestStorage.php | 2 +- src/{ => Server}/ServerApplication.php | 4 +- src/{ => Server}/ServerExpectation.php | 2 +- tests/Matcher/ExtractorFactoryTest.php | 4 +- tests/Matcher/StringMatcherTest.php | 4 +- 14 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 depfile.yaml rename src/{ => Response}/ResponseBuilder.php (91%) rename src/{ => Server}/FileBasedStorage.php (96%) rename src/{ => Server}/RequestStorage.php (92%) rename src/{ => Server}/ServerApplication.php (98%) rename src/{ => Server}/ServerExpectation.php (96%) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1cec7e6..4106962 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -56,3 +56,7 @@ jobs: - name: Check coding style run: composer coding-style continue-on-error: ${{ matrix.experimental }} + + - name: Check dependencies + run: composer dependencies + continue-on-error: ${{ matrix.experimental }} diff --git a/.gitignore b/.gitignore index 094f441..78040de 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ var/ build/* phpunit.xml .phpunit.result.cache +.deptrac.cache diff --git a/composer.json b/composer.json index e2ed91e..d0ca040 100644 --- a/composer.json +++ b/composer.json @@ -31,8 +31,8 @@ "symfony/framework-bundle": "~4|~5" }, "require-dev": { - "internations/testing-component": "1.0.1", - "phpunit/phpunit": "^9" + "phpunit/phpunit": "^9", + "qossmic/deptrac-shim": "^0.13.0" }, "autoload": { "psr-4": {"InterNations\\Component\\HttpMock\\": "src/"} @@ -42,6 +42,7 @@ }, "scripts": { "tests": "phpunit", - "coding-style": "phpcs" + "coding-style": "phpcs", + "dependencies": "deptrac" } } diff --git a/depfile.yaml b/depfile.yaml new file mode 100644 index 0000000..ad8707a --- /dev/null +++ b/depfile.yaml @@ -0,0 +1,114 @@ +paths: + - ./src + - ./tests + - ./vendor/psr + - ./vendor/guzzlehttp + - ./vendor/phpunit + - ./vendor/opis +layers: + - name: "HTTP Mock Client" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\(?!Tests\\|Server\\|Util||ServerProcess).* + - name: "HTTP Mock Server Process" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\ServerProcess$ + - name: "HTTP Mock Server" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\Server\\.+ + - name: "HTTP Mock Util" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\Util$ + - name: "HTTP Mock Tests" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\Tests\\.+ + - name: "PSR HTTP" + collectors: + - type: className + regex: ^Psr\\Http\\.* + - name: "PSR Logger" + collectors: + - type: className + regex: ^Psr\\Log\\.* + - name: "PSR HTTP Discovery" + collectors: + - type: className + regex: ^Http\\Discovery\\* + - name: Guzzle + collectors: + - type: className + regex: ^GuzzleHttp\\.* + - name: PHPUnit + collectors: + - type: className + regex: ^(PHPUnit|SebastianBergmann|DeepCopy|Prophecy|TheSeer|PharIo|Doctrine|Webmozart|PhpParser|phpDocumentor|Composer|Symfony\\Polyfill)\\.* + - name: "Symfony HttpFoundation Component" + collectors: + - type: className + regex: ^Symfony\\Component\\HttpFoundation\\.* + - name: "Symfony Framework Bundle" + collectors: + - type: className + regex: ^Symfony\\Bundle\\FrameworkBundle\\.* + - name: "Symfony HttpKernel Component" + collectors: + - type: className + regex: ^Symfony\\Component\\HttpKernel\\.* + - name: "Symfony DependencyInjection Component" + collectors: + - type: className + regex: ^Symfony\\Component\\DependencyInjection\\.* + - name: "Symfony Routing Component" + collectors: + - type: className + regex: ^Symfony\\Component\\Routing\\.* + - name: "Symfony Process Component" + collectors: + - type: className + regex: ^Symfony\\Component\\Process\\.* + - name: "Opis Serializable Closure" + collectors: + - type: className + regex: ^(Opis\\Closure|SuperClosure) + - name: "hmmmath Fibonacci" + collectors: + - type: className + regex: ^hmmmath\\Fibonacci\\.* +ruleset: + "HTTP Mock Client": + - "Opis Serializable Closure" + - "Symfony HttpFoundation Component" + - "HTTP Mock Util" + - "HTTP Mock Server Process" + "HTTP Mock Server Process": + - "hmmmath Fibonacci" + - "Symfony Process Component" + - "PSR HTTP" + - "PSR HTTP Discovery" + "HTTP Mock Server": + - "Symfony HttpFoundation Component" + - "Symfony HttpKernel Component" + - "Symfony DependencyInjection Component" + - "Symfony Routing Component" + - "Symfony Framework Bundle" + - "HTTP Mock Util" + "HTTP Mock Tests": + - "HTTP Mock Client" + - "HTTP Mock Server Process" + - "Symfony HttpFoundation Component" + - "Opis Serializable Closure" + - "HTTP Mock Util" + - "PSR HTTP" + - "PSR HTTP Discovery" + - PHPUnit + "HTTP Mock Util": ~ + Guzzle: + - "PSR HTTP" + - "PSR Logger" + PHPUnit: ~ + "PSR Logger": + - PHPUnit diff --git a/public/index.php b/public/index.php index 037b674..cc80fac 100644 --- a/public/index.php +++ b/public/index.php @@ -2,6 +2,7 @@ namespace InterNations\Component\HttpMock; use InterNations\Component\HttpMock\Request\SerializableRequest; +use InterNations\Component\HttpMock\Server\ServerApplication; use RuntimeException; use Symfony\Component\HttpFoundation\Request; use function file_exists; diff --git a/src/Expectation.php b/src/Expectation.php index fead5d4..c3661c3 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -5,6 +5,7 @@ use InterNations\Component\HttpMock\Matcher\MatcherFactory; use InterNations\Component\HttpMock\Matcher\Matcher; use Closure; +use InterNations\Component\HttpMock\Response\ResponseBuilder; use Opis\Closure\SerializableClosure; use Symfony\Component\HttpFoundation\Response; diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index 397a8b2..d8df46d 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -2,9 +2,9 @@ namespace InterNations\Component\HttpMock; use Countable; -use GuzzleHttp\Psr7\Response; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Request; use UnexpectedValueException; @@ -59,7 +59,7 @@ public function count(): int /** * @throws UnexpectedValueException */ - private function parseRequestFromResponse(Response $response, string $path): Request + private function parseRequestFromResponse(ResponseInterface $response, string $path): Request { try { return Util::deserialize($response->getBody()); @@ -88,7 +88,7 @@ private function deleteRecordedRequest(string $path): Request ); } - private function parseResponse(Response $response, string $path): Request + private function parseResponse(ResponseInterface $response, string $path): Request { $statusCode = $response->getStatusCode(); diff --git a/src/ResponseBuilder.php b/src/Response/ResponseBuilder.php similarity index 91% rename from src/ResponseBuilder.php rename to src/Response/ResponseBuilder.php index 605e627..07ea51b 100644 --- a/src/ResponseBuilder.php +++ b/src/Response/ResponseBuilder.php @@ -1,7 +1,7 @@ Date: Wed, 19 May 2021 10:49:32 +0200 Subject: [PATCH 37/38] Forward compat --- composer.json | 21 +- depfile.yaml | 2 + src/Server/ServerApplication.php | 3 +- .../UpwardsCompatibleMicroKernelTrait.php | 216 ++++++++++++++++++ src/ServerProcess.php | 24 +- 5 files changed, 245 insertions(+), 21 deletions(-) create mode 100644 src/Server/UpwardsCompatibleMicroKernelTrait.php diff --git a/composer.json b/composer.json index d0ca040..6612cea 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ ], "require": { "php": "~7.4|~8.0", - "symfony/process": "~4|~5", + "symfony/process": "~4.4|~5", "lstrojny/hmmmath": ">=0.5.0", "slevomat/coding-standard": "^7.0", "opis/closure": "^3.6", @@ -23,12 +23,12 @@ "guzzlehttp/psr7": "^1.8", "http-interop/http-factory-guzzle": "^1.0", "php-http/discovery": "^1.13", - "symfony/config": "~4|~5", - "symfony/http-kernel": "~4|~5", - "symfony/http-foundation": "~4|~5", - "symfony/routing": "~4|~5", - "symfony/dependency-injection": "~4|~5", - "symfony/framework-bundle": "~4|~5" + "symfony/config": "~4.4|~5", + "symfony/http-kernel": "~4.4|~5", + "symfony/http-foundation": "~4.4|~5", + "symfony/routing": "~4.4|~5", + "symfony/dependency-injection": "~4.4|~5", + "symfony/framework-bundle": "~4.4|~5" }, "require-dev": { "phpunit/phpunit": "^9", @@ -43,6 +43,11 @@ "scripts": { "tests": "phpunit", "coding-style": "phpcs", - "dependencies": "deptrac" + "dependencies": "deptrac", + "checkup": [ + "@composer tests", + "@composer coding-style", + "@composer dependencies" + ] } } diff --git a/depfile.yaml b/depfile.yaml index ad8707a..7ba36f9 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -5,6 +5,8 @@ paths: - ./vendor/guzzlehttp - ./vendor/phpunit - ./vendor/opis +exclude_files: + - '#.*test.*#' layers: - name: "HTTP Mock Client" collectors: diff --git a/src/Server/ServerApplication.php b/src/Server/ServerApplication.php index 84f5149..47714dc 100644 --- a/src/Server/ServerApplication.php +++ b/src/Server/ServerApplication.php @@ -3,7 +3,6 @@ use InterNations\Component\HttpMock\Util; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; -use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -22,7 +21,7 @@ final class ServerApplication extends Kernel { - use MicroKernelTrait; + use UpwardsCompatibleMicroKernelTrait; /** @return list */ public function registerBundles(): array diff --git a/src/Server/UpwardsCompatibleMicroKernelTrait.php b/src/Server/UpwardsCompatibleMicroKernelTrait.php new file mode 100644 index 0000000..631fddd --- /dev/null +++ b/src/Server/UpwardsCompatibleMicroKernelTrait.php @@ -0,0 +1,216 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace InterNations\Component\HttpMock\Server; + +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader as ContainerPhpFileLoader; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; +use Symfony\Component\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader; +use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\RouteCollectionBuilder; +use function array_keys; +use function class_alias; +use function is_a; +use function sprintf; +use function strpos; +use function trigger_deprecation; + +/** + * A Kernel that provides configuration hooks. + * + * @author Ryan Weaver + * @author Fabien Potencier + * + * @method void configureRoutes(RoutingConfigurator $routes) + * @method void configureContainer(ContainerConfigurator $container) + */ +trait Symfony4MicroKernelTrait +{ + /** + * Adds or imports routes into your application. + * + * $routes->import($this->getProjectDir().'/config/*.{yaml,php}'); + * $routes + * ->add('admin_dashboard', '/admin') + * ->controller('App\Controller\AdminController::dashboard') + * ; + */ + //abstract protected function configureRoutes(RoutingConfigurator $routes): void; + + /** + * Configures the container. + * + * You can register extensions: + * + * $c->extension('framework', [ + * 'secret' => '%secret%' + * ]); + * + * Or services: + * + * $c->services()->set('halloween', 'FooBundle\HalloweenProvider'); + * + * Or parameters: + * + * $c->parameters()->set('halloween', 'lot of fun'); + */ + //abstract protected function configureContainer(ContainerConfigurator $container): void; + + /** + * {@inheritdoc} + */ + public function getCacheDir(): string + { + if (isset($_SERVER['APP_CACHE_DIR'])) { + return $_SERVER['APP_CACHE_DIR'].'/'.$this->environment; + } + + return parent::getCacheDir(); + } + + /** + * {@inheritdoc} + */ + public function getLogDir(): string + { + return $_SERVER['APP_LOG_DIR'] ?? parent::getLogDir(); + } + + /** + * {@inheritdoc} + */ + public function registerBundles(): iterable + { + $contents = require $this->getProjectDir().'/config/bundles.php'; + foreach ($contents as $class => $envs) { + if ($envs[$this->environment] ?? $envs['all'] ?? false) { + yield new $class(); + } + } + } + + /** + * {@inheritdoc} + */ + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load(function (ContainerBuilder $container) use ($loader) { + $container->loadFromExtension('framework', [ + 'router' => [ + 'resource' => 'kernel::loadRoutes', + 'type' => 'service', + ], + ]); + + $kernelClass = false !== strpos(static::class, "@anonymous\0") ? parent::class : static::class; + + if (!$container->hasDefinition('kernel')) { + $container->register('kernel', $kernelClass) + ->addTag('controller.service_arguments') + ->setAutoconfigured(true) + ->setSynthetic(true) + ->setPublic(true) + ; + } + + $kernelDefinition = $container->getDefinition('kernel'); + $kernelDefinition->addTag('routing.route_loader'); + + $container->addObjectResource($this); + $container->fileExists($this->getProjectDir().'/config/bundles.php'); + + try { + $configureContainer = new \ReflectionMethod($this, 'configureContainer'); + } catch (\ReflectionException $e) { + throw new \LogicException(sprintf('"%s" uses "%s", but does not implement the required method "protected function configureContainer(ContainerConfigurator $container): void".', get_debug_type($this), MicroKernelTrait::class), 0, $e); + } + + $configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) instanceof \ReflectionNamedType && !$type->isBuiltin() ? $type->getName() : null; + + if ($configuratorClass && !is_a(ContainerConfigurator::class, $configuratorClass, true)) { + $this->configureContainer($container, $loader); + + return; + } + + // the user has opted into using the ContainerConfigurator + /* @var ContainerPhpFileLoader $kernelLoader */ + $kernelLoader = $loader->getResolver()->resolve($file = $configureContainer->getFileName()); + $kernelLoader->setCurrentDir(\dirname($file)); + $instanceof = &\Closure::bind(function &() { return $this->instanceof; }, $kernelLoader, $kernelLoader)(); + + + try { + $this->configureContainer(new ContainerConfigurator($container, $kernelLoader, $instanceof, $file, $file), $loader); + } finally { + $instanceof = []; + $kernelLoader->registerAliasesForSinglyImplementedInterfaces(); + } + + $container->setAlias($kernelClass, 'kernel')->setPublic(true); + }); + } + + /** + * @internal + * + * @return RouteCollection + */ + public function loadRoutes(LoaderInterface $loader) + { + $file = (new \ReflectionObject($this))->getFileName(); + /* @var RoutingPhpFileLoader $kernelLoader */ + $kernelLoader = $loader->getResolver()->resolve($file, 'php'); + $kernelLoader->setCurrentDir(\dirname($file)); + $collection = new RouteCollection(); + + try { + $configureRoutes = new \ReflectionMethod($this, 'configureRoutes'); + } catch (\ReflectionException $e) { + throw new \LogicException(sprintf('"%s" uses "%s", but does not implement the required method "protected function configureRoutes(RoutingConfigurator $routes): void".', get_debug_type($this), MicroKernelTrait::class), 0, $e); + } + + $configuratorClass = $configureRoutes->getNumberOfParameters() > 0 && ($type = $configureRoutes->getParameters()[0]->getType()) && !$type->isBuiltin() ? $type->getName() : null; + + if ($configuratorClass && !is_a(RoutingConfigurator::class, $configuratorClass, true)) { + trigger_deprecation('symfony/framework-bundle', '5.1', 'Using type "%s" for argument 1 of method "%s:configureRoutes()" is deprecated, use "%s" instead.', RouteCollectionBuilder::class, self::class, RoutingConfigurator::class); + + $routes = new RouteCollectionBuilder($loader); + $this->configureRoutes($routes); + + return $routes->build(); + } + + $this->configureRoutes(new RoutingConfigurator($collection, $kernelLoader, $file, $file)); + + foreach ($collection as $route) { + $controller = $route->getDefault('_controller'); + + if (\is_array($controller) && [0, 1] === array_keys($controller) && $this === $controller[0]) { + $route->setDefault('_controller', ['kernel', $controller[1]]); + } + } + + return $collection; + } +} + +if (version_compare(Kernel::VERSION, '5.0.0', '<')) { + class_alias(Symfony4MicroKernelTrait::class, UpwardsCompatibleMicroKernelTrait::class); +} else { + class_alias(MicroKernelTrait::class, UpwardsCompatibleMicroKernelTrait::class); +} diff --git a/src/ServerProcess.php b/src/ServerProcess.php index c53b913..c41a74b 100644 --- a/src/ServerProcess.php +++ b/src/ServerProcess.php @@ -172,15 +172,17 @@ private static function cleanErrorOutput(string $output): string continue; } - if (strpos($line, 'JIT is incompatible with third party extensions') !== false) { - continue; - } - - if (strpos($line, '[info]') !== false) { - continue; - } - - if (self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { + if (self::stringContainsAny( + $line, + [ + 'Accepted', + 'Closing', + 'Development Server', + 'JIT is incompatible with third party extensions', + ' [info] ', + ' [debug] ', + ] + )) { continue; } @@ -191,10 +193,10 @@ private static function cleanErrorOutput(string $output): string } /** @param list $needles */ - private static function stringEndsWithAny(string $haystack, array $needles): bool + private static function stringContainsAny(string $haystack, array $needles): bool { foreach ($needles as $needle) { - if (substr($haystack, (-1 * strlen($needle))) === $needle) { + if (strpos($haystack, $needle) !== false) { return true; } } From cd52a62136c98b1b66eca6edbd564a3a91f7e79c Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Wed, 19 May 2021 11:47:44 +0200 Subject: [PATCH 38/38] Fix dependencies --- depfile.yaml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/depfile.yaml b/depfile.yaml index 7ba36f9..43446a1 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -6,12 +6,16 @@ paths: - ./vendor/phpunit - ./vendor/opis exclude_files: - - '#.*test.*#' + - '#vendor/.*test.*#' layers: - name: "HTTP Mock Client" collectors: - type: className - regex: ^InterNations\\Component\\HttpMock\\(?!Tests\\|Server\\|Util||ServerProcess).* + regex: ^InterNations\\Component\\HttpMock\\(?!Tests\\|Server\\|Util|Http|ServerProcess).* + - name: "HTTP Mock PSR Middleware" + collectors: + - type: className + regex: ^InterNations\\Component\\HttpMock\\Http\\.* - name: "HTTP Mock Server Process" collectors: - type: className @@ -83,14 +87,18 @@ layers: ruleset: "HTTP Mock Client": - "Opis Serializable Closure" - - "Symfony HttpFoundation Component" - "HTTP Mock Util" - "HTTP Mock Server Process" + - "PSR HTTP" + - "PSR HTTP Discovery" + - "Symfony HttpFoundation Component" "HTTP Mock Server Process": - "hmmmath Fibonacci" - "Symfony Process Component" - "PSR HTTP" - "PSR HTTP Discovery" + - "HTTP Mock PSR Middleware" + - "HTTP Mock Client" "HTTP Mock Server": - "Symfony HttpFoundation Component" - "Symfony HttpKernel Component" @@ -108,6 +116,8 @@ ruleset: - "PSR HTTP Discovery" - PHPUnit "HTTP Mock Util": ~ + "HTTP Mock PSR Middleware": + - "PSR HTTP" Guzzle: - "PSR HTTP" - "PSR Logger"