diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 9b8a8c5..4106962 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
@@ -12,11 +12,17 @@ jobs:
fail-fast: false
matrix:
php-version:
- - 7.1
- - 7.2
- - 7.3
- 7.4
+ - 8.0
experimental: [false]
+ dependencies: [lowest, stable]
+ include:
+ - php-version: 8.1
+ experimental: true
+ dependencies: lowest
+ - php-version: 8.1
+ experimental: true
+ dependencies: stable
continue-on-error: ${{ matrix.experimental }}
steps:
@@ -34,6 +40,7 @@ jobs:
uses: ramsey/composer-install@v1
with:
composer-options: --prefer-dist
+ dependency-versions: ${{ matrix.dependencies }}
continue-on-error: ${{ matrix.experimental }}
- name: Setup PCOV
@@ -45,3 +52,11 @@ 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 }}
+
+ - name: Check dependencies
+ run: composer dependencies
+ continue-on-error: ${{ matrix.experimental }}
diff --git a/.gitignore b/.gitignore
index 7278a54..78040de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
vendor/
composer.lock
.idea/
-state/*-*
+var/
build/*
phpunit.xml
+.phpunit.result.cache
+.deptrac.cache
diff --git a/composer.json b/composer.json
index 6a612fc..6612cea 100644
--- a/composer.json
+++ b/composer.json
@@ -13,17 +13,26 @@
}
],
"require": {
- "php": "~7.1",
- "silex/silex": "~2.0",
- "guzzle/guzzle": ">=3.8",
- "symfony/process": "~3|~4|~5",
- "jeremeamia/superclosure": "~2",
- "lstrojny/hmmmath": ">=0.5.0"
- },
+ "php": "~7.4|~8.0",
+ "symfony/process": "~4.4|~5",
+ "lstrojny/hmmmath": ">=0.5.0",
+ "slevomat/coding-standard": "^7.0",
+ "opis/closure": "^3.6",
+ "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",
+ "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": {
- "internations/kodierungsregelwerksammlung": "~0.23.0",
- "internations/testing-component": "1.0.1",
- "phpunit/phpunit": "^7"
+ "phpunit/phpunit": "^9",
+ "qossmic/deptrac-shim": "^0.13.0"
},
"autoload": {
"psr-4": {"InterNations\\Component\\HttpMock\\": "src/"}
@@ -32,6 +41,13 @@
"psr-4": {"InterNations\\Component\\HttpMock\\Tests\\": "tests/"}
},
"scripts": {
- "tests": "phpunit"
+ "tests": "phpunit",
+ "coding-style": "phpcs",
+ "dependencies": "deptrac",
+ "checkup": [
+ "@composer tests",
+ "@composer coding-style",
+ "@composer dependencies"
+ ]
}
}
diff --git a/depfile.yaml b/depfile.yaml
new file mode 100644
index 0000000..43446a1
--- /dev/null
+++ b/depfile.yaml
@@ -0,0 +1,126 @@
+paths:
+ - ./src
+ - ./tests
+ - ./vendor/psr
+ - ./vendor/guzzlehttp
+ - ./vendor/phpunit
+ - ./vendor/opis
+exclude_files:
+ - '#vendor/.*test.*#'
+layers:
+ - name: "HTTP Mock Client"
+ collectors:
+ - type: className
+ 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
+ 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"
+ - "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"
+ - "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": ~
+ "HTTP Mock PSR Middleware":
+ - "PSR HTTP"
+ Guzzle:
+ - "PSR HTTP"
+ - "PSR Logger"
+ PHPUnit: ~
+ "PSR Logger":
+ - PHPUnit
diff --git a/doc/start.md b/doc/start.md
index b972367..39b34d3 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()
@@ -44,10 +45,10 @@ class ExampleTest extends PHPUnit_Framework_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()
+ public function testAccessingRecordedRequests(): void
{
$this->http->mock
->when()
@@ -58,10 +59,10 @@ class ExampleTest extends PHPUnit_Framework_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/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000..78a1d66
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,76 @@
+
+
+
+ ./src
+ ./tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 51c72a8..07a6982 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,6 +1,6 @@
+
+
+
+
+
+
./tests/
@@ -17,8 +23,7 @@
-
-
+
@@ -26,5 +31,6 @@
+
diff --git a/public/index.php b/public/index.php
index d9d901e..cc80fac 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,8 +1,47 @@
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/Expectation.php b/src/Expectation.php
index 1429b22..c3661c3 100644
--- a/src/Expectation.php
+++ b/src/Expectation.php
@@ -3,29 +3,21 @@
use InterNations\Component\HttpMock\Matcher\ExtractorFactory;
use InterNations\Component\HttpMock\Matcher\MatcherFactory;
-use InterNations\Component\HttpMock\Matcher\MatcherInterface;
-use SuperClosure\SerializableClosure;
+use InterNations\Component\HttpMock\Matcher\Matcher;
use Closure;
+use InterNations\Component\HttpMock\Response\ResponseBuilder;
+use Opis\Closure\SerializableClosure;
+use Symfony\Component\HttpFoundation\Response;
class Expectation
{
- /** @var MatcherInterface[] */
- private $matcher = [];
-
- /** @var MatcherFactory */
- private $matcherFactory;
-
- /** @var ResponseBuilder */
- private $responseBuilder;
-
- /** @var Closure */
- private $limiter;
-
- /** @var ExtractorFactory */
- private $extractorFactory;
-
- /** @var int */
- private $priority;
+ /** @var array */
+ private array $matcher = [];
+ private MatcherFactory $matcherFactory;
+ private ResponseBuilder $responseBuilder;
+ private Closure $limiter;
+ private ExtractorFactory $extractorFactory;
+ private int $priority;
public function __construct(
MockBuilder $mockBuilder,
@@ -42,42 +34,46 @@ public function __construct(
$this->priority = $priority;
}
- public function pathIs($matcher)
+ /** @param string|Matcher $matcher */
+ public function pathIs($matcher): self
{
$this->appendMatcher($matcher, $this->extractorFactory->createPathExtractor());
return $this;
}
- public function methodIs($matcher)
+ /** @param string|Matcher $matcher */
+ public function methodIs($matcher): self
{
$this->appendMatcher($matcher, $this->extractorFactory->createMethodExtractor());
return $this;
}
- public function queryParamIs($param, $matcher)
+ /** @param string|Matcher $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);
@@ -86,7 +82,8 @@ public function queryParamsAre(array $paramMap)
return $this;
}
- public function queryParamsExist(array $params)
+ /** @param array $params */
+ public function queryParamsExist(array $params): self
{
foreach ($params as $param) {
$this->queryParamExists($param);
@@ -95,7 +92,8 @@ public function queryParamsExist(array $params)
return $this;
}
- public function queryParamsNotExist(array $params)
+ /** @param array $params */
+ public function queryParamsNotExist(array $params): self
{
foreach ($params as $param) {
$this->queryParamNotExists($param);
@@ -104,29 +102,30 @@ public function queryParamsNotExist(array $params)
return $this;
}
- public function headerIs($name, $value)
+ /** @param string|Matcher $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));
return $this;
}
- /** @return SerializableClosure[] */
- public function getMatcherClosures()
+ /** @return array */
+ public function getMatcherClosures(): array
{
$closures = [];
@@ -137,27 +136,28 @@ public function getMatcherClosures()
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);
}
- private function appendMatcher($matcher, Closure $extractor = null)
+ /** @param string|Matcher $matcher */
+ private function appendMatcher($matcher, Closure $extractor = null): void
{
$matcher = $this->createMatcher($matcher);
@@ -168,8 +168,9 @@ private function appendMatcher($matcher, Closure $extractor = null)
$this->matcher[] = $matcher;
}
- private function createMatcher($matcher)
+ /** @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/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 @@
+ */
+ private SplStack $middlewareStack;
+
+ public function __construct(ClientInterface $client, ClientMiddleware ...$middlewareStack)
+ {
+ $this->client = $client;
+ $this->middlewareStack = array_reduce(
+ $middlewareStack,
+ static function (SplStack $stack, ClientMiddleware $middleware) {
+ $stack->push($middleware);
+
+ return $stack;
+ },
+ new SplStack()
+ );
+ }
+
+ public function sendRequest(RequestInterface $request): ResponseInterface
+ {
+ return self::createNext(clone $this->middlewareStack)($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);
+ }
+}
diff --git a/src/Matcher/ClosureMatcher.php b/src/Matcher/ClosureMatcher.php
index c528e67..1362c34 100644
--- a/src/Matcher/ClosureMatcher.php
+++ b/src/Matcher/ClosureMatcher.php
@@ -3,16 +3,16 @@
use Closure;
-class ClosureMatcher extends AbstractMatcher
+class ClosureMatcher extends ExtractorBasedMatcher
{
- 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/AbstractMatcher.php b/src/Matcher/ExtractorBasedMatcher.php
similarity index 66%
rename from src/Matcher/AbstractMatcher.php
rename to src/Matcher/ExtractorBasedMatcher.php
index 429d60b..4aa16cc 100644
--- a/src/Matcher/AbstractMatcher.php
+++ b/src/Matcher/ExtractorBasedMatcher.php
@@ -2,19 +2,19 @@
namespace InterNations\Component\HttpMock\Matcher;
use Closure;
-use SuperClosure\SerializableClosure;
+use Opis\Closure\SerializableClosure;
use Symfony\Component\HttpFoundation\Request;
-abstract class AbstractMatcher implements MatcherInterface
+abstract class ExtractorBasedMatcher implements Matcher
{
- 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/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/Matcher.php b/src/Matcher/Matcher.php
new file mode 100644
index 0000000..ae9c8cf
--- /dev/null
+++ b/src/Matcher/Matcher.php
@@ -0,0 +1,11 @@
+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..c863b6d 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..32cbc80 100644
--- a/src/MockBuilder.php
+++ b/src/MockBuilder.php
@@ -11,20 +11,16 @@ class MockBuilder
private const PRIORITY_EXACTLY = 10;
private const PRIORITY_NTH = 100;
- /** @var Expectation[] */
- private $expectations = [];
+ /** @var array */
+ 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)
{
@@ -33,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;
@@ -58,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;
@@ -93,8 +89,8 @@ public function any()
return $this;
}
- /** @return Expectation */
- public function when()
+ /***/
+ public function when(): Expectation
{
$this->expectations[] = new Expectation(
$this,
@@ -109,7 +105,8 @@ public function when()
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 9b0dbbf..347bc86 100644
--- a/src/PHPUnit/HttpMockFacade.php
+++ b/src/PHPUnit/HttpMockFacade.php
@@ -1,77 +1,70 @@
*/
+ 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 = new ServerProcess($port, $host);
$server->start();
$this->services['server'] = $server;
$this->basePath = $basePath;
}
- public static function getProperties()
+ /** @return list */
+ public static function getProperties(): array
{
return ['server', 'matches', 'mock', 'requests', 'client'];
}
- public function setUp()
+ 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;
+ return new RequestCollectionFacade($this->client, Psr17FactoryDiscovery::findRequestFactory());
default:
throw new RuntimeException(sprintf('Invalid property "%s" read', $property));
- break;
}
}
@@ -80,7 +73,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..602ac4d 100644
--- a/src/PHPUnit/HttpMockFacadeMap.php
+++ b/src/PHPUnit/HttpMockFacadeMap.php
@@ -8,14 +8,19 @@
/** @property-read HttpMockFacade */
class HttpMockFacadeMap implements ArrayAccess
{
- /** @var HttpMockFacade[] */
- private $facadeMap;
+ /** @var array */
+ private array $facadeMap;
+ /** @param array $facadeMap */
public function __construct(array $facadeMap)
{
$this->facadeMap = $facadeMap;
}
+ /**
+ * @param int|string $offset
+ * @return mixed
+ */
public function offsetGet($offset)
{
if (!$this->offsetExists($offset)) {
@@ -25,17 +30,23 @@ public function offsetGet($offset)
return $this->facadeMap[$offset];
}
- public function offsetExists($offset)
+ /** @param int|string $offset */
+ public function offsetExists($offset): bool
{
return isset($this->facadeMap[$offset]);
}
- public function offsetSet($offset, $value)
+ /**
+ * @param int|string $offset
+ * @param mixed $value
+ */
+ public function offsetSet($offset, $value): void // @codingStandardsIgnoreLine
{
throw new BadMethodCallException(__METHOD__);
}
- public function offsetUnset($offset)
+ /** @param int|string $offset */
+ public function offsetUnset($offset): void // @codingStandardsIgnoreLine
{
throw new BadMethodCallException(__METHOD__);
}
@@ -50,12 +61,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(string $property): void
{
if (in_array($property, HttpMockFacade::getProperties(), true)) {
throw new OutOfBoundsException(
@@ -77,7 +88,8 @@ public function __get($property)
);
}
- 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 51afa3d..d4bd3b4 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()
- {
- static::assertHttpMockSetup();
-
- $this->http = clone static::$staticHttp;
- }
-
- protected static function assertHttpMockSetup()
- {
- 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()
- {
- if (!$this->http) {
- return;
- }
-
- $http = $this->http;
- $this->http = null;
- $http->each(
- function (HttpMockFacade $facade) {
- $this->assertSame(
- '',
- (string) $facade->server->getIncrementalErrorOutput(),
- 'HTTP mock server standard error output should be empty'
- );
- }
- );
- }
-
- protected static function tearDownHttpMockAfterClass()
- {
- static::$staticHttp->each(
- static function (HttpMockFacade $facade) {
- $facade->server->stop();
- ServerManager::getInstance()->remove($facade->server);
- }
- );
- }
+trait HttpMockTrait // @codingStandardsIgnoreLine
+{
+ use HttpMock;
}
diff --git a/src/PHPUnit/ServerManager.php b/src/PHPUnit/ServerManager.php
index 7f24e90..e608822 100644
--- a/src/PHPUnit/ServerManager.php
+++ b/src/PHPUnit/ServerManager.php
@@ -1,41 +1,34 @@
*/
+ private SplObjectStorage $servers;
- private static $instance;
+ private static ?self $instance = null;
- /**
- * @return self
- */
- public static function getInstance()
+ 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)
+ public function add(ServerProcess $server): void
{
$this->servers->attach($server);
}
- public function remove(Server $server)
+ public function remove(ServerProcess $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/SerializableRequest.php b/src/Request/SerializableRequest.php
new file mode 100644
index 0000000..42c0f96
--- /dev/null
+++ b/src/Request/SerializableRequest.php
@@ -0,0 +1,64 @@
+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,
+ ]);
+ }
+
+ /** @param array $data */
+ public function unserialize($data): void // @codingStandardsIgnoreLine
+ {
+ $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/Request/UnifiedRequest.php b/src/Request/UnifiedRequest.php
deleted file mode 100644
index 45dfed3..0000000
--- a/src/Request/UnifiedRequest.php
+++ /dev/null
@@ -1,312 +0,0 @@
-wrapped = $wrapped;
- $this->init($params);
- }
-
- /**
- * Get the user agent of the request
- *
- * @return string
- */
- public function getUserAgent()
- {
- return $this->userAgent;
- }
-
- /**
- * Get the body of the request if set
- *
- * @return EntityBodyInterface|null
- */
- public function getBody()
- {
- return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args());
- }
-
- /**
- * Get a POST field from the request
- *
- * @param string $field Field to retrieve
- *
- * @return mixed|null
- */
- public function getPostField($field)
- {
- return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args());
- }
-
- /**
- * Get the post fields that will be used in the request
- *
- * @return QueryString
- */
- public function getPostFields()
- {
- return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args());
- }
-
- /**
- * Returns an associative array of POST field names to PostFileInterface objects
- *
- * @return array
- */
- public function getPostFiles()
- {
- return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args());
- }
-
- /**
- * 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($fieldName)
- {
- return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args());
- }
-
- /**
- * Get application and plugin specific parameters set on the message.
- *
- * @return Collection
- */
- public function getParams()
- {
- 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($header)
- {
- return $this->wrapped->getHeader($header);
- }
-
- /**
- * Get all headers as a collection
- *
- * @return HeaderCollection
- */
- public function getHeaders()
- {
- return $this->wrapped->getHeaders();
- }
-
- /**
- * Get an array of message header lines
- *
- * @return array
- */
- public function getHeaderLines()
- {
- 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($header)
- {
- return $this->wrapped->hasHeader($header);
- }
-
- /**
- * Get the raw message headers as a string
- *
- * @return string
- */
- public function getRawHeaders()
- {
- return $this->wrapped->getRawHeaders();
- }
-
- /**
- * Get the collection of key value pairs that will be used as the query
- * string in the request
- *
- * @return QueryString
- */
- public function getQuery()
- {
- return $this->wrapped->getQuery();
- }
-
- /**
- * Get the HTTP method of the request
- *
- * @return string
- */
- public function getMethod()
- {
- return $this->wrapped->getMethod();
- }
-
- /**
- * Get the URI scheme of the request (http, https, ftp, etc)
- *
- * @return string
- */
- public function getScheme()
- {
- return $this->wrapped->getScheme();
- }
-
- /**
- * Get the host of the request
- *
- * @return string
- */
- public function getHost()
- {
- return $this->wrapped->getHost();
- }
-
- /**
- * Get the HTTP protocol version of the request
- *
- * @return string
- */
- public function getProtocolVersion()
- {
- return $this->wrapped->getProtocolVersion();
- }
-
- /**
- * Get the path of the request (e.g. '/', '/index.html')
- *
- * @return string
- */
- public function getPath()
- {
- return $this->wrapped->getPath();
- }
-
- /**
- * Get the port that the request will be sent on if it has been set
- *
- * @return int|null
- */
- public function getPort()
- {
- return $this->wrapped->getPort();
- }
-
- /**
- * Get the username to pass in the URL if set
- *
- * @return string|null
- */
- public function getUsername()
- {
- return $this->wrapped->getUsername();
- }
-
- /**
- * Get the password to pass in the URL if set
- *
- * @return string|null
- */
- public function getPassword()
- {
- 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($asObject = false)
- {
- return $this->wrapped->getUrl($asObject);
- }
-
- /**
- * Get an array of Cookies
- *
- * @return array
- */
- public function getCookies()
- {
- return $this->wrapped->getCookies();
- }
-
- /**
- * Get a cookie value by name
- *
- * @param string $name Cookie to retrieve
- *
- * @return null|string
- */
- public function getCookie($name)
- {
- return $this->wrapped->getCookie($name);
- }
-
- protected function invokeWrappedIfEntityEnclosed($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);
- }
-
- private function init(array $params)
- {
- foreach ($params as $property => $value) {
- if (property_exists($this, $property)) {
- $this->{$property} = $value;
- }
- }
- }
-}
diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php
index 850723e..d8df46d 100644
--- a/src/RequestCollectionFacade.php
+++ b/src/RequestCollectionFacade.php
@@ -2,91 +2,67 @@
namespace InterNations\Component\HttpMock;
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 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;
+ private ClientInterface $client;
+ private RequestFactoryInterface $requestFactory;
- public function __construct(ClientInterface $client)
+ public function __construct(ClientInterface $client, RequestFactoryInterface $requestFactory)
{
$this->client = $client;
+ $this->requestFactory = $requestFactory;
}
- /**
- * @return UnifiedRequest
- */
- public function latest()
+ public function latest(): Request
{
return $this->getRecordedRequest('/_request/last');
}
- /**
- * @return UnifiedRequest
- */
- public function last()
+ public function last(): Request
{
return $this->getRecordedRequest('/_request/last');
}
- /**
- * @return UnifiedRequest
- */
- public function first()
+ public function first(): Request
{
return $this->getRecordedRequest('/_request/first');
}
- /**
- * @param int $position
- * @return UnifiedRequest
- */
- public function at($position)
+ public function at(int $position): Request
{
return $this->getRecordedRequest('/_request/' . $position);
}
- /**
- * @return UnifiedRequest
- */
- public function pop()
+ public function pop(): Request
{
return $this->deleteRecordedRequest('/_request/last');
}
- /**
- * @return UnifiedRequest
- */
- public function shift()
+ public function shift(): Request
{
return $this->deleteRecordedRequest('/_request/first');
}
- public function count()
+ public function count(): int
{
- $response = $this->client
- ->get('/_request/count')
- ->send();
-
- return (int) $response->getBody(true);
+ return (int) (string) $this->client->sendRequest(
+ $this->requestFactory->createRequest('GET', '/_request/count')
+ )->getBody();
}
/**
- * @param Response $response
- * @param string $path
* @throws UnexpectedValueException
- * @return UnifiedRequest
*/
- private function parseRequestFromResponse(Response $response, $path)
+ private function parseRequestFromResponse(ResponseInterface $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()),
@@ -94,63 +70,25 @@ private function parseRequestFromResponse(Response $response, $path)
$e
);
}
-
- $request = RequestFactory::getInstance()->fromMessage($requestInfo['request']);
- $params = $this->configureRequest(
- $request,
- $requestInfo['server'],
- isset($requestInfo['enclosure']) ? $requestInfo['enclosure'] : []
- );
-
- return new UnifiedRequest($request, $params);
- }
-
- private function configureRequest(RequestInterface $request, array $server, array $enclosure)
- {
- 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'], isset($server['PHP_AUTH_PW']) ? $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($path)
+ private function getRecordedRequest(string $path): Request
{
- $response = $this->client
- ->get($path)
- ->send();
-
- return $this->parseResponse($response, $path);
+ return $this->parseResponse(
+ $this->client->sendRequest($this->requestFactory->createRequest('GET', $path)),
+ $path
+ );
}
- private function deleteRecordedRequest($path)
+ private function deleteRecordedRequest(string $path): Request
{
- $response = $this->client
- ->delete($path)
- ->send();
-
- return $this->parseResponse($response, $path);
+ return $this->parseResponse(
+ $this->client->sendRequest($this->requestFactory->createRequest('DELETE', $path)),
+ $path
+ );
}
- private function parseResponse(Response $response, $path)
+ private function parseResponse(ResponseInterface $response, string $path): Request
{
$statusCode = $response->getStatusCode();
@@ -160,11 +98,9 @@ private function parseResponse(Response $response, $path)
);
}
- $contentType = $response->hasHeader('content-type')
- ? $response->getContentType()
- : '';
+ $contentType = $response->getHeaderLine('content-type');
- 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
deleted file mode 100644
index f2838f8..0000000
--- a/src/RequestStorage.php
+++ /dev/null
@@ -1,61 +0,0 @@
-pid = $pid;
- $this->directory = $directory;
- }
-
- public function store(Request $request, $name, $data)
- {
- file_put_contents($this->getFileName($request, $name), serialize($data));
- }
-
- public function read(Request $request, $name)
- {
- $fileName = $this->getFileName($request, $name);
-
- if (!file_exists($fileName)) {
- return [];
- }
-
- return Util::deserialize(file_get_contents($fileName));
- }
-
- public function append(Request $request, $name, $data)
- {
- $list = $this->read($request, $name);
- $list[] = $data;
- $this->store($request, $name, $list);
- }
-
- public function prepend(Request $request, $name, $data)
- {
- $list = $this->read($request, $name);
- array_unshift($list, $data);
- $this->store($request, $name, $list);
- }
-
- private function getFileName(Request $request, $name)
- {
- return $this->directory . $this->pid . '-' . $name . '-' . $request->server->get('SERVER_PORT');
- }
-
- public function clear(Request $request, $name)
- {
- $fileName = $this->getFileName($request, $name);
-
- if (file_exists($fileName)) {
- unlink($fileName);
- }
- }
-}
diff --git a/src/Response/CallbackResponse.php b/src/Response/CallbackResponse.php
index 025979c..c49d71e 100644
--- a/src/Response/CallbackResponse.php
+++ b/src/Response/CallbackResponse.php
@@ -5,22 +5,25 @@
class CallbackResponse extends Response
{
+ /** @var callable */
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;
- $callback($this);
+ if (!$this->callback) {
+ return;
}
+
+ $callback = $this->callback;
+ $callback($this);
}
- public function send()
+ public function send(): void
{
$this->sendCallback();
parent::send();
diff --git a/src/ResponseBuilder.php b/src/Response/ResponseBuilder.php
similarity index 52%
rename from src/ResponseBuilder.php
rename to src/Response/ResponseBuilder.php
index 62890ba..07ea51b 100644
--- a/src/ResponseBuilder.php
+++ b/src/Response/ResponseBuilder.php
@@ -1,17 +1,15 @@
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
deleted file mode 100644
index b1b7a8c..0000000
--- a/src/Server.php
+++ /dev/null
@@ -1,164 +0,0 @@
-port = $port;
- $this->host = $host;
- $packageRoot = __DIR__ . '/../';
- $command = [
- 'php',
- '-dalways_populate_raw_post_data=-1',
- '-derror_log=',
- '-S=' . $this->getConnectionString(),
- '-t=public/',
- $packageRoot . 'public/index.php',
- ];
-
- parent::__construct($command, $packageRoot);
- $this->setTimeout(null);
- }
-
- public function start(callable $callback = null, array $env = [])
- {
- parent::start($callback, $env);
-
- $this->pollWait();
- }
-
- public function stop($timeout = 10, $signal = null)
- {
- return parent::stop($timeout, $signal);
- }
-
- public function getClient()
- {
- return $this->client ?: $this->client = $this->createClient();
- }
-
- private function createClient()
- {
- $client = new Client($this->getBaseUrl());
- $client->getEventDispatcher()->addListener(
- 'request.error',
- static function (Event $event) {
- $event->stopPropagation();
- }
- );
-
- return $client;
- }
-
- public function getBaseUrl()
- {
- return sprintf('http://%s', $this->getConnectionString());
- }
-
- public function getConnectionString()
- {
- return sprintf('%s:%d', $this->host, $this->port);
- }
-
- /**
- * @param Expectation[] $expectations
- * @throws RuntimeException
- */
- public function setUp(array $expectations)
- {
- /** @var Expectation $expectation */
- foreach ($expectations as $expectation) {
- $response = $this->getClient()->post(
- '/_expectation',
- null,
- [
- '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');
- }
- }
- }
-
- public function clean()
- {
- if (!$this->isRunning()) {
- $this->start();
- }
-
- $this->getClient()->delete('/_all')->send();
- }
-
- private function pollWait()
- {
- foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) {
- try {
- usleep($sleepTime);
- $this->getClient()->head('/_me')->send();
- break;
- } catch (CurlException $e) {
- continue;
- }
- }
- }
-
- public function getIncrementalErrorOutput()
- {
- return self::cleanErrorOutput(parent::getIncrementalErrorOutput());
- }
-
- public function getErrorOutput()
- {
- return self::cleanErrorOutput(parent::getErrorOutput());
- }
-
- private static function cleanErrorOutput($output)
- {
- if (!trim($output)) {
- return '';
- }
-
- $errorLines = [];
-
- foreach (explode(PHP_EOL, $output) as $line) {
- if (!$line) {
- continue;
- }
-
- if (!self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) {
- $errorLines[] = $line;
- }
- }
-
- return $errorLines ? implode(PHP_EOL, $errorLines) : '';
- }
-
- private static function stringEndsWithAny($haystack, array $needles)
- {
- foreach ($needles as $needle) {
- if (substr($haystack, (-1 * strlen($needle))) === $needle) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/src/Server/FileBasedStorage.php b/src/Server/FileBasedStorage.php
new file mode 100644
index 0000000..8ac450f
--- /dev/null
+++ b/src/Server/FileBasedStorage.php
@@ -0,0 +1,99 @@
+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/Server/RequestStorage.php b/src/Server/RequestStorage.php
new file mode 100644
index 0000000..cca6d03
--- /dev/null
+++ b/src/Server/RequestStorage.php
@@ -0,0 +1,19 @@
+ $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/Server/ServerApplication.php b/src/Server/ServerApplication.php
new file mode 100644
index 0000000..47714dc
--- /dev/null
+++ b/src/Server/ServerApplication.php
@@ -0,0 +1,244 @@
+ */
+ 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, FileBasedStorage::class)
+ ->autowire()
+ ->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, 'deleteAll'])
+ ->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 self::createResponse(Response::HTTP_I_AM_A_TEAPOT, 'O RLY?');
+ }
+
+ public function deleteAll(RequestStorage $requestStorage): Response
+ {
+ $requestStorage->storeRequests([]);
+ $requestStorage->storeExpectations([]);
+
+ return self::createResponse(Response::HTTP_OK);
+ }
+
+ public function deleteRequests(RequestStorage $requestStorage): Response
+ {
+ $requestStorage->storeRequests([]);
+
+ return self::createResponse(Response::HTTP_OK);
+ }
+
+ public function getRequestByIndex(int $index, RequestStorage $requestStorage): Response
+ {
+ $requests = $requestStorage->readRequests();
+
+ if (!isset($requests[$index])) {
+ return self::createResponse(Response::HTTP_NOT_FOUND, 'Index ' . $index . ' not found');
+ }
+
+ return self::createResponse(Response::HTTP_OK, serialize($requests[$index]));
+ }
+
+ public function getRequestByPosition(string $position, RequestStorage $requestStorage): Response
+ {
+ $requestData = $requestStorage->readRequests();
+ $fn = 'array_' . ($position === 'last' ? 'pop': 'shift');
+ $request = $fn($requestData);
+
+ if (!$request) {
+ return self::createResponse(Response::HTTP_NOT_FOUND, $position . ' not available');
+ }
+
+ return self::createResponse(Response::HTTP_OK, serialize($request));
+ }
+
+ public function deleteRequestByPosition(string $position, RequestStorage $requestStorage): Response
+ {
+ $requests = $requestStorage->readRequests();
+ $fn = 'array_' . ($position === 'last' ? 'pop' : 'shift');
+ $request = $fn($requests);
+ $requestStorage->storeRequests($requests);
+
+ if (!$request) {
+ return self::createResponse(Response::HTTP_NOT_FOUND, $position . ' not possible');
+ }
+
+ return self::createResponse(Response::HTTP_OK, serialize($request));
+ }
+
+ public function countRequests(RequestStorage $requestStorage): Response
+ {
+ return self::createResponse(Response::HTTP_OK, count($requestStorage->readRequests()));
+ }
+
+ public function postExpectations(Request $currentRequest, RequestStorage $requestStorage): Response
+ {
+ $matcher = [];
+
+ if ($currentRequest->request->has('matcher')) {
+ $matcherParameter = $currentRequest->request->get('matcher');
+ if (!is_string($matcherParameter)) {
+ return self::createResponse(
+ Response::HTTP_EXPECTATION_FAILED,
+ 'POST data key "matcher" must be a serialized list of closures'
+ );
+ }
+
+ $matcher = Util::silentDeserialize($matcherParameter);
+ $validator = static function ($closure) {
+ return is_callable($closure);
+ };
+
+ if (!is_array($matcher) || count(array_filter($matcher, $validator)) !== count($matcher)) {
+ return self::createResponse(
+ Response::HTTP_EXPECTATION_FAILED,
+ 'POST data key "matcher" must be a serialized list of closures'
+ );
+ }
+ }
+
+ 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->prependExpectation(new ServerExpectation($matcher, $response, $limiter, 0));
+
+ return self::createResponse(Response::HTTP_CREATED);
+ }
+
+ public function record(Request $currentRequest, RequestStorage $requestStorage): Response
+ {
+ $requestStorage->appendRequest($currentRequest);
+ $expectations = $requestStorage->readExpectations();
+
+ try {
+ foreach ($expectations as $expectation) {
+ $response = $expectation->matchRequest($currentRequest);
+
+ if (!$response) {
+ continue;
+ }
+
+ return $response;
+ }
+
+ return self::createResponse(Response::HTTP_NOT_FOUND, 'No matching expectation found');
+ } finally {
+ $requestStorage->storeExpectations($expectations);
+ }
+ }
+
+ public function deleteExpectations(RequestStorage $requestStorage): Response
+ {
+ $requestStorage->storeExpectations([]);
+
+ 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/Server/ServerExpectation.php b/src/Server/ServerExpectation.php
new file mode 100644
index 0000000..95fcd67
--- /dev/null
+++ b/src/Server/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/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
new file mode 100644
index 0000000..c41a74b
--- /dev/null
+++ b/src/ServerProcess.php
@@ -0,0 +1,206 @@
+port = $port;
+ $this->host = $host;
+ $packageRoot = __DIR__ . '/../';
+ $command = [
+ 'php',
+ '-dalways_populate_raw_post_data=-1',
+ '-derror_log=',
+ '-S=' . $this->getConnectionString(),
+ '-t=public/',
+ $packageRoot . 'public/index.php',
+ ];
+
+ parent::__construct($command, $packageRoot, ['HTTP_MOCK_TESTSUITE' => getenv('HTTP_MOCK_TESTSUITE')]);
+ $this->setTimeout(null);
+ }
+
+ /** @param array $env */
+ public function start(callable $callback = null, array $env = []): void
+ {
+ parent::start($callback, $env);
+
+ $this->pollWait();
+ }
+
+ /**
+ * @param int|float $timeout
+ * @param int $signal
+ */
+ public function stop($timeout = 10, $signal = null): ?int // @codingStandardsIgnoreLine
+ {
+ return parent::stop($timeout, $signal);
+ }
+
+ public function getClient(): ClientInterface
+ {
+ return $this->client ?: $this->client = $this->createClient();
+ }
+
+ private function createClient(): ClientInterface
+ {
+ return new MiddlewareSupportingClient(
+ Psr18ClientDiscovery::find(),
+ new BaseUriMiddleware($this->getBaseUrl())
+ );
+ }
+
+ public function getBaseUrl(): UriInterface
+ {
+ 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
+ {
+ return sprintf('%s:%d', $this->host, $this->port);
+ }
+
+ /**
+ * @param array $expectations
+ * @throws RuntimeException
+ */
+ public function setUp(array $expectations): void
+ {
+ foreach ($expectations as $expectation) {
+ $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) {
+ throw new RuntimeException('Could not set up expectations');
+ }
+ }
+ }
+
+ public function clean(): void
+ {
+ if (!$this->isRunning()) {
+ $this->start();
+ }
+
+ $this->getClient()->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all'));
+ }
+
+ private function pollWait(): void
+ {
+ foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) {
+ try {
+ usleep($sleepTime);
+ $this->getClient()->sendRequest($this->getRequestFactory()->createRequest('HEAD', '/_me'));
+ break;
+ } catch (ClientExceptionInterface $e) {
+ continue;
+ }
+ }
+ }
+
+ public function getIncrementalErrorOutput(): string
+ {
+ return self::cleanErrorOutput(parent::getIncrementalErrorOutput());
+ }
+
+ public function getErrorOutput(): string
+ {
+ return self::cleanErrorOutput(parent::getErrorOutput());
+ }
+
+ private static function cleanErrorOutput(string $output): string
+ {
+ if (!trim($output)) {
+ return '';
+ }
+
+ $errorLines = [];
+
+ foreach (explode(PHP_EOL, $output) as $line) {
+ if (!$line) {
+ continue;
+ }
+
+ if (self::stringContainsAny(
+ $line,
+ [
+ 'Accepted',
+ 'Closing',
+ 'Development Server',
+ 'JIT is incompatible with third party extensions',
+ ' [info] ',
+ ' [debug] ',
+ ]
+ )) {
+ continue;
+ }
+
+ $errorLines[] = $line;
+ }
+
+ return $errorLines ? implode(PHP_EOL, $errorLines) : '';
+ }
+
+ /** @param list $needles */
+ private static function stringContainsAny(string $haystack, array $needles): bool
+ {
+ foreach ($needles as $needle) {
+ if (strpos($haystack, $needle) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
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
deleted file mode 100644
index 0dd46b3..0000000
--- a/src/app.php
+++ /dev/null
@@ -1,232 +0,0 @@
-delete(
- '/_expectation',
- static function (Request $request) use ($app) {
- $app['storage']->clear($request, 'expectations');
-
- return new Response('', Response::HTTP_OK);
- }
-);
-
-$app->post(
- '/_expectation',
- static function (Request $request) use ($app) {
-
- $matcher = [];
-
- if ($request->request->has('matcher')) {
- $matcher = Util::silentDeserialize($request->request->get('matcher'));
- $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 (!$request->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'));
-
- if (!$response instanceof Response) {
- return new Response(
- 'POST data key "response" must be a serialized Symfony response',
- Response::HTTP_EXPECTATION_FAILED
- );
- }
-
- $limiter = null;
-
- if ($request->request->has('limiter')) {
- $limiter = Util::silentDeserialize($request->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(
- $request,
- 'expectations',
- ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0]
- );
-
- return new Response('', Response::HTTP_CREATED);
- }
-);
-
-$app->error(
- static function (Exception $e, Request $request, $code, GetResponseForExceptionEvent $event = null) use ($app) {
- if ($e instanceof NotFoundHttpException) {
- if (method_exists($event, 'allowCustomResponseCode')) {
- $event->allowCustomResponseCode();
- }
-
- $app['storage']->append(
- $request,
- 'requests',
- serialize(
- [
- 'server' => $request->server->all(),
- 'request' => (string) $request,
- 'enclosure' => $request->request->all(),
- ]
- )
- );
-
- $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND);
-
- $expectations = $app['storage']->read($request, 'expectations');
-
- foreach ($expectations as $pos => $expectation) {
- foreach ($expectation['matcher'] as $matcher) {
- if (!$matcher($request)) {
- continue 2;
- }
- }
-
- $applicable = !isset($expectation['limiter']) || $expectation['limiter']($expectation['runs']);
-
- ++$expectations[$pos]['runs'];
- $app['storage']->store($request, '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 $request) use ($app) {
- return count($app['storage']->read($request, 'requests'));
- }
-);
-
-$app->get(
- '/_request/{index}',
- static function (Request $request, $index) use ($app) {
- $requestData = $app['storage']->read($request, 'requests');
-
- if (!isset($requestData[$index])) {
- return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND);
- }
-
- return new Response($requestData[$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');
- $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift');
- $requestString = $fn($requestData);
- $app['storage']->store($request, 'requests', $requestData);
-
- if (!$requestString) {
- return new Response($action . ' not possible', Response::HTTP_NOT_FOUND);
- }
-
- return new Response($requestString, 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');
- $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift');
- $requestString = $fn($requestData);
-
- if (!$requestString) {
- return new Response($action . ' not available', Response::HTTP_NOT_FOUND);
- }
-
- return new Response($requestString, 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', []);
-
- return new Response('', Response::HTTP_OK);
- }
-);
-
-$app->delete(
- '/_all',
- static function (Request $request) use ($app) {
- $app['storage']->store($request, 'requests', []);
- $app['storage']->store($request, '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 c8d8ebc..8fa0e0a 100644
--- a/tests/AppIntegrationTest.php
+++ b/tests/AppIntegrationTest.php
@@ -1,215 +1,251 @@
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::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',
- null,
- $this->createExpectationParams(
- [
- static function ($request) {
- return $request instanceof Request;
- }
- ],
- new Response('fake body', 200)
- )
- )->send();
- $this->assertSame('', (string) $response->getBody());
- $this->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());
-
- $response = $this->client->get('/_request/latest')->send();
-
- /** @var EntityEnclosingRequest $request */
+ $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->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->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last'));
+
$request = $this->parseRequestFromResponse($response);
- $this->assertSame('1', (string) $request->getHeader('X-Special'));
- $this->assertSame('post=data', (string) $request->getBody());
+ self::assertSame('1', $request->headers->get('X-Special'));
+ self::assertSame('post=data', $request->getContent());
}
- public function testRecording()
+ public function testRecording(): void
{
- $this->client->delete('/_all')->send();
+ $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all'));
- $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->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')->send();
- $this->client->get('/req/1')->send();
- $this->client->get('/req/2')->send();
- $this->client->get('/req/3')->send();
+ $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'));
- $this->assertSame(
+ self::assertSame(
'/req/3',
- $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/last')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/0',
- $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/1',
- $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/1')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/2',
- $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/2')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/3',
- $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/3')))->getRequestUri()
);
- $this->assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode());
+ self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/4'))->getStatusCode());
- $this->assertSame(
+ self::assertSame(
'/req/3',
- $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_request/last')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/0',
- $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_request/first')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/1',
- $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/0')))->getRequestUri()
);
- $this->assertSame(
+ self::assertSame(
'/req/2',
- $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath()
+ $this->parseRequestFromResponse($this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/1')))->getRequestUri()
);
- $this->assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode());
+ self::assertSame(404, $this->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/_request/2'))->getStatusCode());
}
- public function testErrorHandling()
+ public function testErrorHandling(): void
{
- $this->client->delete('/_all')->send();
+ $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all'));
- $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());
-
- $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());
+ $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()
+ );
- $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());
+ $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()
+ );
- $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());
+ $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', 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());
- }
+ $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()
+ );
- public function testServerParamsAreRecorded()
- {
- $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']);
+ $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()
+ public function testNewestExpectationsAreFirstEvaluated(): void
{
- $this->client->post(
- '/_expectation',
- null,
- $this->createExpectationParams(
- [
- static function ($request) {
- return $request instanceof Request;
- }
- ],
- new Response('first', 200)
- )
- )->send();
- $this->assertSame('first', $this->client->get('/')->send()->getBody(true));
-
- $this->client->post(
- '/_expectation',
- null,
- $this->createExpectationParams(
- [
- static function ($request) {
- return $request instanceof Request;
- }
- ],
- new Response('second', 200)
- )
- )->send();
- $this->assertSame('second', $this->client->get('/')->send()->getBody(true));
+ $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()
+ public function testServerLogsAreNotInErrorOutput(): void
{
- $this->client->delete('/_all');
+ $this->client->sendRequest($this->getRequestFactory()->createRequest('DELETE', '/_all'));
$expectedServerErrorOutput = '[404]: (null) / - No such file or directory';
@@ -220,26 +256,28 @@ public function testServerLogsAreNotInErrorOutput()
$actualServerErrorOutput = self::$server1->getErrorOutput();
- $this->assertEquals($expectedServerErrorOutput, $actualServerErrorOutput);
+ self::assertEquals($expectedServerErrorOutput, $actualServerErrorOutput);
self::$server1->clearErrorOutput();
}
- private function parseRequestFromResponse(GuzzleResponse $response)
+ private function parseRequestFromResponse(ResponseInterface $response): Request
{
- $body = unserialize($response->getBody());
-
- return RequestFactory::getInstance()->fromMessage($body['request']);
+ return Util::deserialize($response->getBody());
}
- 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);
}
return [
- 'matcher' => serialize($closures),
+ 'matcher' => serialize($closures),
'response' => serialize($response),
];
}
diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php
index b6d746e..0356251 100644
--- a/tests/Fixtures/Request.php
+++ b/tests/Fixtures/Request.php
@@ -1,16 +1,16 @@
requestUri = $requestUri;
}
- public function setContent($content)
+ public function setContent(string $content): void
{
$this->content = $content;
}
diff --git a/tests/Matcher/ExtractorFactoryTest.php b/tests/Matcher/ExtractorFactoryTest.php
index 3f5f8f7..8932953 100644
--- a/tests/Matcher/ExtractorFactoryTest.php
+++ b/tests/Matcher/ExtractorFactoryTest.php
@@ -2,86 +2,85 @@
namespace InterNations\Component\HttpMock\Tests\Matcher;
use InterNations\Component\HttpMock\Matcher\ExtractorFactory;
-use InterNations\Component\Testing\AbstractTestCase;
-use Symfony\Component\HttpFoundation\Request;
+use InterNations\Component\HttpMock\Tests\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use Symfony\Component\HttpFoundation\Request;
-class ExtractorFactoryTest extends AbstractTestCase
+class ExtractorFactoryTest extends TestCase
{
- /** @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');
+ $this->request = $this->createMock(Request::class);
}
- public function testGetMethod()
+ 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()
+ 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()
+ 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()
+ 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()
+ 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()
+ public function testGetHeaderWithExistingHeader(): void
{
$request = new Request(
[],
@@ -95,10 +94,10 @@ public function testGetHeaderWithExistingHeader()
$extractorFactory = new ExtractorFactory('/foo');
$extractor = $extractorFactory->createHeaderExtractor('content-type');
- $this->assertSame('application/json', $extractor($request));
+ self::assertSame('application/json', $extractor($request));
}
- public function testGetHeaderWithNonExistingHeader()
+ public function testGetHeaderWithNonExistingHeader(): void
{
$request = new Request(
[],
@@ -112,10 +111,10 @@ public function testGetHeaderWithNonExistingHeader()
$extractorFactory = new ExtractorFactory('/foo');
$extractor = $extractorFactory->createHeaderExtractor('content-type');
- $this->assertNull($extractor($request));
+ self::assertNull($extractor($request));
}
- public function testHeaderExistsWithExistingHeader()
+ public function testHeaderExistsWithExistingHeader(): void
{
$request = new Request(
[],
@@ -129,10 +128,10 @@ public function testHeaderExistsWithExistingHeader()
$extractorFactory = new ExtractorFactory('/foo');
$extractor = $extractorFactory->createHeaderExistsExtractor('content-type');
- $this->assertTrue($extractor($request));
+ self::assertTrue($extractor($request));
}
- public function testHeaderExistsWithNonExistingHeader()
+ public function testHeaderExistsWithNonExistingHeader(): void
{
$request = new Request(
[],
@@ -146,6 +145,6 @@ public function testHeaderExistsWithNonExistingHeader()
$extractorFactory = new ExtractorFactory('/foo');
$extractor = $extractorFactory->createHeaderExistsExtractor('content-type');
- $this->assertFalse($extractor($request));
+ self::assertFalse($extractor($request));
}
}
diff --git a/tests/Matcher/StringMatcherTest.php b/tests/Matcher/StringMatcherTest.php
index 32df60c..29c937b 100644
--- a/tests/Matcher/StringMatcherTest.php
+++ b/tests/Matcher/StringMatcherTest.php
@@ -2,17 +2,15 @@
namespace InterNations\Component\HttpMock\Tests\Matcher;
use InterNations\Component\HttpMock\Matcher\StringMatcher;
-use InterNations\Component\Testing\AbstractTestCase;
+use InterNations\Component\HttpMock\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
-class StringMatcherTest extends AbstractTestCase
+class StringMatcherTest extends TestCase
{
- public function testConversionToString()
+ 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 5e06a54..5f81b48 100644
--- a/tests/MockBuilderIntegrationTest.php
+++ b/tests/MockBuilderIntegrationTest.php
@@ -1,12 +1,10 @@
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();
}
- public function tearDown()
+ public function tearDown(): void
{
$this->server->stop();
}
- public function testCreateExpectation()
+ public function testCreateExpectation(): void
{
$builder = $this->builder
->when()
@@ -53,15 +48,15 @@ public function testCreateExpectation()
})
->then()
->statusCode(401)
- ->body('response body')
->header('X-Foo', 'Bar')
+ ->body('response body')
->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);
@@ -72,31 +67,34 @@ public function testCreateExpectation()
$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());
+ $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());
$this->server->setUp($expectations);
$client = $this->server->getClient();
- $this->assertSame('response body', (string) $client->post('/foo')->send()->getBody());
+ self::assertSame(
+ 'response body',
+ (string) $client->sendRequest($this->getRequestFactory()->createRequest('POST', '/foo'))->getBody()
+ );
- $this->assertContains('CLOSURE MATCHER: POST /foo', $this->server->getErrorOutput());
+ self::assertNotFalse(strpos($this->server->getErrorOutput(), 'CLOSURE MATCHER: POST /foo'));
}
- public function testCreateTwoExpectationsAfterEachOther()
+ public function testCreateTwoExpectationsAfterEachOther(): void
{
$this->builder
->when()
@@ -118,13 +116,33 @@ public function testCreateTwoExpectationsAfterEachOther()
->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()->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()
+ public function testCreateSuccessiveExpectationsOnSameWhen(): void
{
$this->builder
->first()
@@ -150,12 +168,27 @@ public function testCreateSuccessiveExpectationsOnSameWhen()
$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()->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()
+ public function testCreateSuccessiveExpectationsWithAny(): void
{
$this->builder
->first()
@@ -181,12 +214,12 @@ public function testCreateSuccessiveExpectationsWithAny()
$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()->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()
+ public function testCreateSuccessiveExpectationsInUnexpectedOrder(): void
{
$this->builder
->second()
@@ -205,11 +238,11 @@ public function testCreateSuccessiveExpectationsInUnexpectedOrder()
$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()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody());
+ self::assertSame('2', (string) $this->server->getClient()->sendRequest($this->getRequestFactory()->createRequest('POST', '/resource'))->getBody());
}
- public function testCreateSuccessiveExpectationsWithOnce()
+ public function testCreateSuccessiveExpectationsWithOnce(): void
{
$this->builder
->first()
@@ -235,10 +268,35 @@ public function testCreateSuccessiveExpectationsWithOnce()
$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()->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(
+ '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 baad498..9df4c66 100644
--- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php
+++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php
@@ -1,49 +1,48 @@
setUpHttpMock();
}
- public function tearDown()
+ public function tearDown(): void
{
$this->tearDownHttpMock();
}
- public static function getPaths()
+ /** @return array */
+ public static function getPaths(): array
{
return [
- [
- '/foo',
- '/bar',
- ]
+ ['/foo'],
+ ['/bar'],
];
}
/** @dataProvider getPaths */
- public function testSimpleRequest($path)
+ public function testSimpleRequest(string $path): void
{
$this->http['firstNamedServer']->mock
->when()
@@ -53,33 +52,38 @@ public function testSimpleRequest($path)
->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->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', $path)
+ )->getBody()
+ );
$request = $this->http['firstNamedServer']->requests->latest();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ 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->getPath());
+ 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->getPath());
+ 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->getPath());
+ 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->getPath());
+ 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->sendRequest($this->getRequestFactory()->createRequest('GET', $path))->getBody());
$request = $this->http['firstNamedServer']->requests->shift();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
$this->expectException('UnexpectedValueException');
@@ -87,46 +91,50 @@ 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();
- $this->http['firstNamedServer']->client->get('/foo')->send();
+ $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();
- $this->fail('Exception expected');
+ self::fail('Exception expected');
} catch (\Exception $e) {
- $this->assertContains('HTTP mock server standard error output should be empty', $e->getMessage());
+ self::assertNotFalse(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty'));
}
}
- 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());
+ $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());
}
- 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());
+ $response = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', '/')
+ );
+ self::assertSame(404, $response->getStatusCode());
}
- public function testLimitDurationOfAResponse()
+ public function testLimitDurationOfAResponse(): void
{
$this->http['firstNamedServer']->mock
->once()
@@ -136,11 +144,15 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http['firstNamedServer']->setUp();
- $firstResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(410, $secondResponse->getStatusCode());
- $this->assertSame('Expectation not met', $secondResponse->getBody(true));
+ $firstResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(200, $firstResponse->getStatusCode());
+ $secondResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(404, $secondResponse->getStatusCode());
+ self::assertSame('No matching expectation found', (string) $secondResponse->getBody());
$this->http['firstNamedServer']->mock
->exactly(2)
@@ -150,13 +162,19 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http['firstNamedServer']->setUp();
- $firstResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $secondResponse->getStatusCode());
- $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(410, $thirdResponse->getStatusCode());
- $this->assertSame('Expectation not met', $thirdResponse->getBody(true));
+ $firstResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(200, $firstResponse->getStatusCode());
+ $secondResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(200, $secondResponse->getStatusCode());
+ $thirdResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(404, $thirdResponse->getStatusCode());
+ self::assertSame('No matching expectation found', (string) $thirdResponse->getBody());
$this->http['firstNamedServer']->mock
->any()
@@ -166,27 +184,38 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http['firstNamedServer']->setUp();
- $firstResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $secondResponse->getStatusCode());
- $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send();
- $this->assertSame(200, $thirdResponse->getStatusCode());
+ $firstResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(200, $firstResponse->getStatusCode());
+ $secondResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::assertSame(200, $secondResponse->getStatusCode());
+ $thirdResponse = $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ );
+ self::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));
+ self::assertSame(
+ 'CALLBACK',
+ (string) $this->http['firstNamedServer']->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ )->getBody()
+ );
}
- public function testComplexResponse()
+ public function testComplexResponse(): void
{
$this->http['firstNamedServer']->mock
->when()
@@ -197,15 +226,22 @@ public function testComplexResponse()
->header('X-Foo', 'Bar')
->end();
$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()->getPostField('post-key'));
+ $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'));
+ self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('post-key'));
}
- public function testPutRequest()
+ public function testPutRequest(): void
{
$this->http['firstNamedServer']->mock
->when()
@@ -216,15 +252,20 @@ public function testPutRequest()
->header('X-Foo', 'Bar')
->end();
$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()->getPostField('put-key'));
+ $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'));
+ self::assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->request->get('put-key'));
}
- public function testPostRequest()
+ public function testPostRequest(): void
{
$this->http['firstNamedServer']->mock
->when()
@@ -235,18 +276,23 @@ public function testPostRequest()
->header('X-Foo', 'Bar')
->end();
$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()->getPostField('post-key'));
+ $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'));
+ self::assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->request->get('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');
+ if (PHP_VERSION_ID < 70000) {
+ 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 8cc8199..4504a24 100644
--- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php
+++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php
@@ -1,35 +1,35 @@
setUpHttpMock();
}
- public function tearDown()
+ public function tearDown(): void
{
$this->tearDownHttpMock();
}
- public function testSimpleRequest()
+ public function testSimpleRequest(): void
{
$this->http->mock
->when()
@@ -39,10 +39,15 @@ public function testSimpleRequest()
->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->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', '/custom-base-path/foo')
+ )->getBody()
+ );
$request = $this->http->requests->latest();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame('/custom-base-path/foo', $request->getPath());
+ 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 39a8518..f8b5db9 100644
--- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php
+++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php
@@ -1,49 +1,48 @@
setUpHttpMock();
}
- public function tearDown()
+ public function tearDown(): void
{
$this->tearDownHttpMock();
}
- public static function getPaths()
+ /** @return array */
+ public static function getPaths(): array
{
return [
- [
- '/foo',
- '/bar',
- ]
+ ['/foo'],
+ ['/bar'],
];
}
/** @dataProvider getPaths */
- public function testSimpleRequest($path)
+ public function testSimpleRequest(string $path): void
{
$this->http->mock
->when()
@@ -53,33 +52,43 @@ public function testSimpleRequest($path)
->end();
$this->http->setUp();
- $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody());
+ self::assertSame(
+ $path . ' body',
+ (string) $this->http->client->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', $path)
+ )->getBody()
+ );
$request = $this->http->requests->latest();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
$request = $this->http->requests->last();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
$request = $this->http->requests->first();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ 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->getPath());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
$request = $this->http->requests->pop();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
-
- $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
+
+ self::assertSame(
+ $path . ' body',
+ (string) $this->http->client->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', $path)
+ )->getBody()
+ );
$request = $this->http->requests->shift();
- $this->assertSame('GET', $request->getMethod());
- $this->assertSame($path, $request->getPath());
+ self::assertSame('GET', $request->getMethod());
+ self::assertSame($path, $request->getRequestUri());
$this->expectException('UnexpectedValueException');
@@ -87,46 +96,46 @@ 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();
- $this->http->client->get('/foo')->send();
+ $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 {
$this->tearDown();
- $this->fail('Exception expected');
+ self::fail('Exception expected');
} catch (\Exception $e) {
- $this->assertContains('HTTP mock server standard error output should be empty', $e->getMessage());
+ self::assertNotFalse(strpos($e->getMessage(), 'HTTP mock server standard error output should be empty'));
}
}
- 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());
+ $response = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo'));
+ self::assertSame(404, $response->getStatusCode());
+ self::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());
+ $response = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/foo'));
+ self::assertSame(404, $response->getStatusCode());
}
- public function testLimitDurationOfAResponse()
+ public function testLimitDurationOfAResponse(): void
{
$this->http->mock
->once()
@@ -136,11 +145,11 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http->setUp();
- $firstResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http->client->post('/')->send();
- $this->assertSame(410, $secondResponse->getStatusCode());
- $this->assertSame('Expectation not met', $secondResponse->getBody(true));
+ $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(404, $secondResponse->getStatusCode());
+ self::assertSame('No matching expectation found', (string) $secondResponse->getBody());
$this->http->mock
->exactly(2)
@@ -150,13 +159,13 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http->setUp();
- $firstResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $secondResponse->getStatusCode());
- $thirdResponse = $this->http->client->post('/')->send();
- $this->assertSame(410, $thirdResponse->getStatusCode());
- $this->assertSame('Expectation not met', $thirdResponse->getBody(true));
+ $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(200, $secondResponse->getStatusCode());
+ $thirdResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/'));
+ self::assertSame(404, $thirdResponse->getStatusCode());
+ self::assertSame('No matching expectation found', (string) $thirdResponse->getBody());
$this->http->mock
->any()
@@ -166,27 +175,32 @@ public function testLimitDurationOfAResponse()
->body('POST METHOD')
->end();
$this->http->setUp();
- $firstResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $firstResponse->getStatusCode());
- $secondResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $secondResponse->getStatusCode());
- $thirdResponse = $this->http->client->post('/')->send();
- $this->assertSame(200, $thirdResponse->getStatusCode());
+ $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(200, $secondResponse->getStatusCode());
+ $thirdResponse = $this->http->client->sendRequest($this->getRequestFactory()->createRequest('POST', '/'));
+ self::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));
+ self::assertSame(
+ 'CALLBACK',
+ (string) $this->http->client->sendRequest(
+ $this->getRequestFactory()->createRequest('POST', '/')
+ )->getBody()
+ );
}
- public function testComplexResponse()
+ public function testComplexResponse(): void
{
$this->http->mock
->when()
@@ -197,15 +211,20 @@ public function testComplexResponse()
->body('BODY')
->end();
$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()->getPostField('post-key'));
+ $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'));
+ self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key'));
}
- public function testPutRequest()
+ public function testPutRequest(): void
{
$this->http->mock
->when()
@@ -216,15 +235,20 @@ public function testPutRequest()
->header('X-Foo', 'Bar')
->end();
$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()->getPostField('put-key'));
+ $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'));
+ self::assertSame('put-value', $this->http->requests->latest()->request->get('put-key'));
}
- public function testPostRequest()
+ public function testPostRequest(): void
{
$this->http->mock
->when()
@@ -235,15 +259,20 @@ public function testPostRequest()
->header('X-Foo', 'Bar')
->end();
$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()->getPostField('post-key'));
+ $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'));
+ self::assertSame('post-value', $this->http->requests->latest()->request->get('post-key'));
}
- public function testCountRequests()
+ public function testCountRequests(): void
{
$this->http->mock
->when()
@@ -253,17 +282,22 @@ public function testCountRequests()
->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->sendRequest(
+ $this->getRequestFactory()->createRequest('GET', '/resource')
+ )->getBody()
+ );
+ self::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');
}
)
@@ -273,13 +307,21 @@ function (Request $request) {
->end();
$this->http->setUp();
- $this->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(
+ '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()
+ public function testMatchRegex(): void
{
$this->http->mock
->when()
@@ -289,11 +331,17 @@ public function testMatchRegex()
->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->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody()
+ );
+ self::assertSame(
+ 'response',
+ (string) $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/'))->getBody()
+ );
}
- public function testMatchQueryParams()
+ public function testMatchQueryParams(): void
{
$this->http->mock
->when()
@@ -308,28 +356,31 @@ public function testMatchQueryParams()
->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(
+ (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')->send()->getStatusCode()
+ $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p1=&p2=v2&p3=foo'))
+ ->getStatusCode()
);
- $this->assertSame(
+ self::assertSame(
Response::HTTP_NOT_FOUND,
- $this->http->client->get('/?p1=')->send()->getStatusCode()
+ $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p1='))->getStatusCode()
);
- $this->assertSame(
+ self::assertSame(
Response::HTTP_NOT_FOUND,
- $this->http->client->get('/?p3=foo')->send()->getStatusCode()
+ $this->http->client->sendRequest($this->getRequestFactory()->createRequest('GET', '/?p3=foo'))
+ ->getStatusCode()
);
}
- 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');
+ if (PHP_VERSION_ID < 70000) {
+ 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
deleted file mode 100644
index 479a384..0000000
--- a/tests/Request/UnifiedRequestTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-wrappedRequest = $this->createMock('Guzzle\Http\Message\RequestInterface');
- $this->wrappedEntityEnclosingRequest = $this->createMock('Guzzle\Http\Message\EntityEnclosingRequestInterface');
- $this->unifiedRequest = new UnifiedRequest($this->wrappedRequest);
- $this->unifiedEnclosingEntityRequest = new UnifiedRequest($this->wrappedEntityEnclosingRequest);
- }
-
- public static function provideMethods()
- {
- return [
- ['getParams'],
- ['getHeaders'],
- ['getHeaderLines'],
- ['getRawHeaders'],
- ['getQuery'],
- ['getMethod'],
- ['getScheme'],
- ['getHost'],
- ['getProtocolVersion'],
- ['getPath'],
- ['getPort'],
- ['getUsername'],
- ['getPassword'],
- ['getUrl'],
- ['getCookies'],
- ['getHeader', ['header']],
- ['hasHeader', ['header']],
- ['getUrl', [false]],
- ['getUrl', [true]],
- ['getCookie', ['cookieName']],
- ];
- }
-
- public static function provideEntityEnclosingInterfaceMethods()
- {
- return [
- ['getBody'],
- ['getPostField', ['postField']],
- ['getPostFields'],
- ['getPostFiles'],
- ['getPostFile', ['fileName']],
- ];
- }
-
- /** @dataProvider provideMethods */
- public function testMethodsFromRequestInterface($method, array $params = [])
- {
- $this->wrappedRequest
- ->expects($this->once())
- ->method($method)
- ->will($this->returnValue('REQ'))
- ->with(...$params);
- $this->assertSame('REQ', call_user_func_array([$this->unifiedRequest, $method], $params));
-
-
- $this->wrappedEntityEnclosingRequest
- ->expects($this->once())
- ->method($method)
- ->will($this->returnValue('ENTITY_ENCL_REQ'))
- ->with(...$params);
- $this->assertSame(
- 'ENTITY_ENCL_REQ',
- call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params)
- );
- }
-
- /** @dataProvider provideEntityEnclosingInterfaceMethods */
- public function testEntityEnclosingInterfaceMethods($method, array $params = [])
- {
- $this->wrappedEntityEnclosingRequest
- ->expects($this->once())
- ->method($method)
- ->will($this->returnValue('ENTITY_ENCL_REQ'))
- ->with(...$params);
-
- $this->assertSame(
- 'ENTITY_ENCL_REQ',
- call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params)
- );
-
- $this->wrappedRequest
- ->expects($this->any())
- ->method('getMethod')
- ->will($this->returnValue('METHOD'));
- $this->wrappedRequest
- ->expects($this->any())
- ->method('getPath')
- ->will($this->returnValue('/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()
- {
- $this->assertNull($this->unifiedRequest->getUserAgent());
-
- $unifiedRequest = new UnifiedRequest($this->wrappedRequest, ['userAgent' => 'UA']);
- $this->assertSame('UA', $unifiedRequest->getUserAgent());
- }
-}
diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php
index e111263..118406b 100644
--- a/tests/RequestCollectionFacadeTest.php
+++ b/tests/RequestCollectionFacadeTest.php
@@ -1,34 +1,28 @@
client = $this->createMock('Guzzle\Http\ClientInterface');
- $this->facade = new RequestCollectionFacade($this->client);
- $this->request = new Request('GET', '/_request/last');
- $this->request->setClient($this->client);
+ $this->client = $this->createMock(ClientInterface::class);
+ $this->facade = new RequestCollectionFacade($this->client, $this->getRequestFactory());
}
- public static function provideMethodAndUrls()
+ /** @return array,3:string}> */
+ public static function getMethodAndUrls(): array
{
return [
['latest', '/_request/last'],
@@ -40,158 +34,194 @@ public static function provideMethodAndUrls()
];
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestingLatestRequest($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ 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);
+ /** @var \Symfony\Component\HttpFoundation\Request $request */
+ $request = $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->getRequestUri());
+ self::assertSame('RECORDED=1', $request->getContent());
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestLatestResponseWithHttpAuth($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ 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());
+ /** @var \Symfony\Component\HttpFoundation\Request $request */
+ $request = $this->facade->{$method}(...$args);
+
+ self::assertSame('POST', $request->getMethod());
+ 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->getUser());
+ self::assertSame('password', $request->getPassword());
+ self::assertSame('CUSTOM UA', $request->headers->get('User-Agent'));
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestResponse_InvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ public function testRequestResponseWithInvalidStatusCode(
+ string $method,
+ string $path,
+ array $args = [],
+ string $httpMethod = 'get'
+ ): void
{
$this->mockClient($path, $this->createResponseWithInvalidStatusCode(), $httpMethod);
$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);
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestResponse_EmptyContentType($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ public function testRequestResponseWithEmptyContentType(
+ string $method,
+ string $path,
+ array $args = [],
+ string $httpMethod = 'get'
+ ): void
{
$this->mockClient($path, $this->createResponseWithEmptyContentType(), $httpMethod);
$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);
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestResponse_InvalidContentType($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ public function testRequestResponseWithInvalidContentType(
+ string $method,
+ string $path,
+ array $args = [],
+ string $httpMethod = 'get'
+ ): void
{
$this->mockClient($path, $this->createResponseWithInvalidContentType(), $httpMethod);
$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);
}
- /** @dataProvider provideMethodAndUrls */
- public function testRequestResponse_DeserializationError($method, $path, array $args = [], $httpMethod = 'get')
+ /**
+ * @dataProvider getMethodAndUrls
+ * @param array $args
+ */
+ public function testRequestResponseWithDeserializationError(
+ string $method,
+ string $path,
+ array $args = [],
+ string $httpMethod = 'get'
+ ): void
{
$this->mockClient($path, $this->createResponseThatCannotBeDeserialized(), $httpMethod);
$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($path, Response $response, $method)
+ private function mockClient(string $path, ResponseInterface $response, string $method): void
{
$this->client
- ->expects($this->once())
- ->method($method)
- ->with($path)
- ->will($this->returnValue($this->request));
-
- $this->client
- ->expects($this->once())
- ->method('send')
- ->with($this->request)
- ->will($this->returnValue($response));
+ ->expects(self::once())
+ ->method('sendRequest')
+ ->with($this->getRequestFactory()->createRequest($method, $path))
+ ->willReturn($response);
}
- private function createSimpleResponse()
+ private function createSimpleResponse(): ResponseInterface
{
$recordedRequest = new TestRequest();
$recordedRequest->setMethod('POST');
$recordedRequest->setRequestUri('/foo');
$recordedRequest->setContent('RECORDED=1');
- return new Response(
- '200',
- ['Content-Type' => 'text/plain'],
- serialize(
- [
- 'server' => [],
- 'request' => (string) $recordedRequest,
- ]
- )
- );
+ return $this->getResponseFactory()
+ ->createResponse()
+ ->withHeader('Content-Type', 'text/plain')
+ ->withBody($this->getStreamFactory()->createStream(serialize($recordedRequest)));
}
- private function createComplexResponse()
+ private function createComplexResponse(): ResponseInterface
{
$recordedRequest = new TestRequest();
$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');
-
- 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,
- ]
- )
- );
+ $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 $this->getResponseFactory()
+ ->createResponse()
+ ->withHeader('Content-Type', 'text/plain; charset=UTF-8')
+ ->withBody($this->getStreamFactory()->createStream(serialize($recordedRequest)));
}
- private function createResponseWithInvalidStatusCode()
+ private function createResponseWithInvalidStatusCode(): ResponseInterface
{
- return new Response(404);
+ return $this->getResponseFactory()
+ ->createResponse(404);
}
- private function createResponseWithInvalidContentType()
+ private function createResponseWithInvalidContentType(): ResponseInterface
{
- return new Response(200, ['Content-Type' => 'text/html']);
+ return $this->getResponseFactory()
+ ->createResponse()
+ ->withHeader('Content-Type', 'text/html');
}
- private function createResponseWithEmptyContentType()
+ private function createResponseWithEmptyContentType(): ResponseInterface
{
- return new Response(200, []);
+ return $this->getResponseFactory()
+ ->createResponse();
}
- private function createResponseThatCannotBeDeserialized()
+ 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 @@
+