regexp, form-data and multipart form request matchers

This commit is contained in:
Pavel 2021-09-23 19:41:02 +03:00
parent 064b07940c
commit dd441f54db
19 changed files with 863 additions and 10 deletions

View File

@ -122,9 +122,9 @@ In order to use unsupported serializer you should create a decorator which imple
- [x] `replyWithCallback` - reply using specified callback.
- [x] `replyWithFactory` - reply using specified response factory (provide corresponding interface).
- [x] Compare XML bodies using `DOMDocument`, fallback to text comparison in case of problems.
- [ ] Regexp matchers for body, query and path.
- [ ] Form Data body matcher (partial & exact)
- [ ] Multipart form body matcher (partial & exact)
- [x] Regexp matchers for body, query, URI and path.
- [x] Form Data body matcher (partial & exact)
- [x] Multipart form body matcher (just like callback matcher but parses the body as a multipart form data)
- [ ] `symfony/http-client` support.
- [ ] Real network response for mocked & unmatched requests.
- [ ] Document everything (with examples if its feasible).

View File

@ -36,7 +36,8 @@
"psr/http-client": "^1.0",
"psr/http-message": "^1.0",
"php-http/httplug": "^1.0 || ^2.0",
"nyholm/psr7": "^1.4"
"nyholm/psr7": "^1.4",
"riverline/multipart-parser": "^2.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.6",
@ -47,7 +48,8 @@
"jms/serializer": "^2 | ^3.12",
"symfony/phpunit-bridge": "^5.2",
"symfony/serializer": "^5.2",
"symfony/property-access": "^5.2"
"symfony/property-access": "^5.2",
"php-http/multipart-stream-builder": "^1.2"
},
"provide": {
"psr/http-client-implementation": "1.0",

View File

@ -0,0 +1,41 @@
<?php
/**
* PHP version 7.3
*
* @category AbstractRegExpMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
/**
* Class AbstractRegExpMatcher
*
* @category AbstractRegExpMatcher
* @package Pock\Matchers
*/
abstract class AbstractRegExpMatcher implements RequestMatcherInterface
{
/** @var string */
protected $expression;
/** @var int */
protected $flags = 0;
/**
* @param string $expression
* @param int $flags
*/
public function __construct(string $expression, int $flags = 0)
{
$this->expression = $expression;
$this->flags = $flags;
}
protected function matchRegExp(string $content): bool
{
$matches = [];
return 1 === preg_match($this->expression, $content, $matches, $this->flags);
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* PHP version 7.3
*
* @category ExactFormDataMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Pock\Comparator\ComparatorLocator;
use Pock\Comparator\RecursiveArrayComparator;
use Pock\Traits\SeekableStreamDataExtractor;
use Psr\Http\Message\RequestInterface;
/**
* Class ExactFormDataMatcher
*
* @category ExactFormDataMatcher
* @package Pock\Matchers
*/
class ExactFormDataMatcher extends QueryMatcher
{
use SeekableStreamDataExtractor;
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
$query = static::parseQuery(static::getStreamData($request->getBody()));
if (empty($query)) {
return false;
}
return ComparatorLocator::get(RecursiveArrayComparator::class)->compare($this->query, $query);
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* PHP version 7.3
*
* @category FormDataMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Pock\Comparator\ComparatorLocator;
use Pock\Comparator\RecursiveLtrArrayComparator;
use Pock\Traits\SeekableStreamDataExtractor;
use Psr\Http\Message\RequestInterface;
/**
* Class FormDataMatcher
*
* @category FormDataMatcher
* @package Pock\Matchers
*/
class FormDataMatcher extends QueryMatcher
{
use SeekableStreamDataExtractor;
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
$query = static::parseQuery(static::getStreamData($request->getBody()));
if (empty($query)) {
return false;
}
return ComparatorLocator::get(RecursiveLtrArrayComparator::class)->compare($this->query, $query);
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* PHP version 7.1
*
* @category MultipartFormDataMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use InvalidArgumentException;
use Pock\Traits\SeekableStreamDataExtractor;
use Psr\Http\Message\RequestInterface;
use Riverline\MultiPartParser\StreamedPart;
use Riverline\MultiPartParser\Converters\PSR7;
use RuntimeException;
/**
* Class MultipartFormDataMatcher
*
* @category MultipartFormDataMatcher
* @package Pock\Matchers
*/
class MultipartFormDataMatcher implements RequestMatcherInterface
{
use SeekableStreamDataExtractor;
/** @var callable */
private $callback;
/**
* MultipartFormDataMatcher constructor.
*
* @param callable $callback Accepts Riverline\MultiPartParser\StreamedPart as an argument, returns true if matched.
*/
public function __construct(callable $callback)
{
$this->callback = $callback;
}
/**
* @inheritDoc
* @SuppressWarnings(PHPMD.StaticAccess)
*/
public function matches(RequestInterface $request): bool
{
try {
$part = PSR7::convert($request);
$request->getBody()->rewind();
} catch (InvalidArgumentException $exception) {
return false;
}
return call_user_func($this->callback, $part);
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpBodyMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Pock\Traits\SeekableStreamDataExtractor;
use Psr\Http\Message\RequestInterface;
/**
* Class RegExpBodyMatcher
*
* @category RegExpBodyMatcher
* @package Pock\Matchers
*/
class RegExpBodyMatcher extends AbstractRegExpMatcher
{
use SeekableStreamDataExtractor;
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
return $this->matchRegExp(static::getStreamData($request->getBody()));
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpPathMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Psr\Http\Message\RequestInterface;
/**
* Class RegExpPathMatcher
*
* @category RegExpPathMatcher
* @package Pock\Matchers
*/
class RegExpPathMatcher extends AbstractRegExpMatcher
{
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
return $this->matchRegExp($request->getUri()->getPath());
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpQueryMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Psr\Http\Message\RequestInterface;
/**
* Class RegExpQueryMatcher
*
* @category RegExpQueryMatcher
* @package Pock\Matchers
*/
class RegExpQueryMatcher extends AbstractRegExpMatcher
{
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
return $this->matchRegExp($request->getUri()->getQuery());
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpUriMatcher
* @package Pock\Matchers
*/
namespace Pock\Matchers;
use Psr\Http\Message\RequestInterface;
/**
* Class RegExpUriMatcher
*
* @category RegExpUriMatcher
* @package Pock\Matchers
*/
class RegExpUriMatcher extends AbstractRegExpMatcher
{
/**
* @inheritDoc
*/
public function matches(RequestInterface $request): bool
{
return $this->matchRegExp((string) $request->getUri());
}
}

View File

@ -9,22 +9,20 @@
namespace Pock;
use Diff\ArrayComparer\StrictArrayComparer;
use DOMDocument;
use Pock\Enum\RequestMethod;
use Pock\Enum\RequestScheme;
use Pock\Exception\PockClientException;
use Pock\Exception\PockNetworkException;
use Pock\Exception\PockRequestException;
use Pock\Exception\XmlException;
use Pock\Factory\CallbackReplyFactory;
use Pock\Factory\ReplyFactoryInterface;
use Pock\Matchers\AnyRequestMatcher;
use Pock\Matchers\BodyMatcher;
use Pock\Matchers\CallbackRequestMatcher;
use Pock\Matchers\ExactFormDataMatcher;
use Pock\Matchers\ExactHeaderMatcher;
use Pock\Matchers\ExactHeadersMatcher;
use Pock\Matchers\ExactQueryMatcher;
use Pock\Matchers\FormDataMatcher;
use Pock\Matchers\HeaderLineMatcher;
use Pock\Matchers\HeaderLineRegexpMatcher;
use Pock\Matchers\HeaderMatcher;
@ -32,9 +30,14 @@ use Pock\Matchers\HeadersMatcher;
use Pock\Matchers\HostMatcher;
use Pock\Matchers\JsonBodyMatcher;
use Pock\Matchers\MethodMatcher;
use Pock\Matchers\MultipartFormDataMatcher;
use Pock\Matchers\MultipleMatcher;
use Pock\Matchers\PathMatcher;
use Pock\Matchers\QueryMatcher;
use Pock\Matchers\RegExpBodyMatcher;
use Pock\Matchers\RegExpPathMatcher;
use Pock\Matchers\RegExpQueryMatcher;
use Pock\Matchers\RegExpUriMatcher;
use Pock\Matchers\RequestMatcherInterface;
use Pock\Matchers\SchemeMatcher;
use Pock\Matchers\UriMatcher;
@ -55,6 +58,7 @@ use Throwable;
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*/
class PockBuilder
{
@ -169,6 +173,19 @@ class PockBuilder
return $this->addMatcher(new UriMatcher($uri));
}
/**
* Matches request by the whole URI using regular expression.
*
* @param string $expression
* @param int $flags
*
* @return self
*/
public function matchUriRegExp(string $expression, int $flags = 0): self
{
return $this->addMatcher(new RegExpUriMatcher($expression, $flags));
}
/**
* Matches request by header value or several values. Header can have other values which are not specified here.
* @see PockBuilder::matchExactHeader() if you want to match exact header values.
@ -262,6 +279,20 @@ class PockBuilder
return $this->addMatcher(new PathMatcher($path));
}
/**
* Match request by its path using regular expression. This matcher doesn't care about prefix slash
* since it's pretty easy to do it using regular expression.
*
* @param string $expression
* @param int $flags
*
* @return self
*/
public function matchPathRegExp(string $expression, int $flags = 0): self
{
return $this->addMatcher(new RegExpPathMatcher($expression, $flags));
}
/**
* Match request by its query. Request can contain other query variables.
* @see PockBuilder::matchExactQuery() if you want to match an entire query string.
@ -275,6 +306,19 @@ class PockBuilder
return $this->addMatcher(new QueryMatcher($query));
}
/**
* Match request by its query using regular expression.
*
* @param string $expression
* @param int $flags
*
* @return self
*/
public function matchQueryRegExp(string $expression, int $flags = 0): self
{
return $this->addMatcher(new RegExpQueryMatcher($expression, $flags));
}
/**
* Match request by its query. Additional query parameters aren't allowed.
*
@ -287,6 +331,44 @@ class PockBuilder
return $this->addMatcher(new ExactQueryMatcher($query));
}
/**
* Match request with form-data.
*
* @param array<string, mixed> $formFields
*
* @return self
*/
public function matchFormData(array $formFields): self
{
return $this->addMatcher(new FormDataMatcher($formFields));
}
/**
* Match request with form-data. Additional fields aren't allowed.
*
* @param array<string, mixed> $formFields
*
* @return self
*/
public function matchExactFormData(array $formFields): self
{
return $this->addMatcher(new ExactFormDataMatcher($formFields));
}
/**
* Match request multipart form data. Will not match the request if body is not multipart.
* Uses third-party library to parse the data.
*
* @param callable $callback Accepts Riverline\MultiPartParser\StreamedPart as an argument, returns true if matched.
*
* @return self
* @see https://github.com/Riverline/multipart-parser#usage
*/
public function matchMultipartFormData(callable $callback): self
{
return $this->addMatcher(new MultipartFormDataMatcher($callback));
}
/**
* Match entire request body.
*
@ -299,6 +381,19 @@ class PockBuilder
return $this->addMatcher(new BodyMatcher($data));
}
/**
* Match entire request body using provided regular expression.
*
* @param string $expression
* @param int $flags
*
* @return self
*/
public function matchBodyRegExp(string $expression, int $flags = 0): self
{
return $this->addMatcher(new RegExpBodyMatcher($expression, $flags));
}
/**
* Match JSON request body.
*
@ -373,7 +468,7 @@ class PockBuilder
* Match request using provided callback. Callback should receive RequestInterface and return boolean.
* If returned value is true then request is matched.
*
* @param callable $callback
* @param callable $callback Callable that accepts PSR-7 RequestInterface as it's first argument.
*
* @return self
*/

View File

@ -0,0 +1,62 @@
<?php
/**
* PHP version 7.3
*
* @category ExactFormDataMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\ExactFormDataMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class ExactFormDataMatcherTest
*
* @category ExactFormDataMatcherTest
* @package Pock\Tests\Matchers
*/
class ExactFormDataMatcherTest extends PockTestCase
{
public function testInvalidData(): void
{
$matcher = new ExactFormDataMatcher(['field3' => 'value3']);
$request = self::getRequestWithBody('doesn\'t look like form-data at all');
self::assertFalse($matcher->matches($request));
}
public function testNoMatches(): void
{
$matcher = new ExactFormDataMatcher(['field3' => 'value3']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertFalse($matcher->matches($request));
}
public function testNoMatchesByValue(): void
{
$matcher = new ExactFormDataMatcher(['field1' => 'value2']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertFalse($matcher->matches($request));
}
public function testNoMatchesRedundantParam(): void
{
$matcher = new ExactFormDataMatcher(['field2' => 'value2']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new ExactFormDataMatcher(['field1' => 'value1', 'field2' => 'value2']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertTrue($matcher->matches($request));
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* PHP version 7.3
*
* @category FormDataMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\FormDataMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class FormDataMatcherTest
*
* @category FormDataMatcherTest
* @package Pock\Tests\Matchers
*/
class FormDataMatcherTest extends PockTestCase
{
public function testInvalidData(): void
{
$matcher = new FormDataMatcher(['field3' => 'value3']);
$request = self::getRequestWithBody('doesn\'t look like form-data at all');
self::assertFalse($matcher->matches($request));
}
public function testNoMatches(): void
{
$matcher = new FormDataMatcher(['field3' => 'value3']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertFalse($matcher->matches($request));
}
public function testNoMatchesByValue(): void
{
$matcher = new FormDataMatcher(['field1' => 'value2']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new FormDataMatcher(['field2' => 'value2']);
$request = self::getRequestWithBody('field1=value1&field2=value2');
self::assertTrue($matcher->matches($request));
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* PHP version 7.3
*
* @category MultipartFormDataMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Http\Message\MultipartStream\MultipartStreamBuilder;
use Pock\Matchers\MultipartFormDataMatcher;
use Pock\TestUtils\PockTestCase;
use Psr\Http\Message\RequestInterface;
use Riverline\MultiPartParser\StreamedPart;
/**
* Class MultipartFormDataMatcherTest
*
* @category MultipartFormDataMatcherTest
* @package Pock\Tests\Matchers
*/
class MultipartFormDataMatcherTest extends PockTestCase
{
public function testNoMatchesNotMultipart(): void
{
$matcher = new MultipartFormDataMatcher(function (StreamedPart $part) {
return $part->isMultiPart();
});
self::assertFalse($matcher->matches(self::getTestRequest()));
self::assertFalse($matcher->matches(self::getRequestWithBody('param=value&param2=value')));
}
public function testMatches(): void
{
$matcher = new MultipartFormDataMatcher(function (StreamedPart $part) {
return $part->isMultiPart() &&
1 === count($part->getPartsByName('param1')) &&
1 === count($part->getPartsByName('param2')) &&
'value1' === $part->getPartsByName('param1')[0]->getBody() &&
'value2' === $part->getPartsByName('param2')[0]->getBody() &&
'text/plain' === $part->getPartsByName('param1')[0]->getHeader('Content-Type');
});
$builder = new MultipartStreamBuilder(self::getPsr17Factory());
$builder->addResource('param1', 'value1', ['headers' => ['Content-Type' => 'text/plain']])
->addResource('param2', 'value2');
self::assertTrue($matcher->matches(self::getMultipartRequest($builder)));
}
private static function getMultipartRequest(MultipartStreamBuilder $builder): RequestInterface
{
return self::getPsr17Factory()->createRequest('POST', 'https://example.com')
->withHeader('Content-Type', 'multipart/form-data; boundary="' . $builder->getBoundary() . '"')
->withBody($builder->build());
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpBodyMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\RegExpBodyMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class RegExpBodyMatcherTest
*
* @category RegExpBodyMatcherTest
* @package Pock\Tests\Matchers
*/
class RegExpBodyMatcherTest extends PockTestCase
{
public function testNoMatches(): void
{
$matcher = new RegExpBodyMatcher('/\d+-\d+/m');
$request = static::getRequestWithBody('test unmatchable request');
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new RegExpBodyMatcher('/\d+-\d+/m', PREG_UNMATCHED_AS_NULL);
$request = static::getRequestWithBody('23-900');
self::assertTrue($matcher->matches($request));
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpPathMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\RegExpPathMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class RegExpPathMatcherTest
*
* @category RegExpPathMatcherTest
* @package Pock\Tests\Matchers
*/
class RegExpPathMatcherTest extends PockTestCase
{
public function testNoMatches(): void
{
$matcher = new RegExpPathMatcher('/\/?\d+-\d+/m');
$request = static::getTestRequest()->withUri(static::getPsr17Factory()->createUri('https://test.com/test'));
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new RegExpPathMatcher('/\d+-\d+/m', PREG_UNMATCHED_AS_NULL);
$request = static::getTestRequest()->withUri(static::getPsr17Factory()->createUri('https://test.com/23-900'));
self::assertTrue($matcher->matches($request));
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpQueryMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\RegExpQueryMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class RegExpQueryMatcherTest
*
* @category RegExpQueryMatcherTest
* @package Pock\Tests\Matchers
*/
class RegExpQueryMatcherTest extends PockTestCase
{
public function testNoMatches(): void
{
$matcher = new RegExpQueryMatcher('/\d+-\d+/m');
$request = static::getTestRequest()->withUri(
static::getPsr17Factory()->createUri('https://test.com')
->withQuery('param=value')
);
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new RegExpQueryMatcher('/\d+-\d+/m', PREG_UNMATCHED_AS_NULL);
$request = static::getTestRequest()->withUri(
static::getPsr17Factory()->createUri('https://test.com')
->withQuery('param=23-900')
);
self::assertTrue($matcher->matches($request));
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* PHP version 7.3
*
* @category RegExpUriMatcherTest
* @package Pock\Tests\Matchers
*/
namespace Pock\Tests\Matchers;
use Pock\Matchers\RegExpUriMatcher;
use Pock\TestUtils\PockTestCase;
/**
* Class RegExpUriMatcherTest
*
* @category RegExpUriMatcher
* @package Pock\Tests\Matchers
*/
class RegExpUriMatcherTest extends PockTestCase
{
public function testNoMatches(): void
{
$matcher = new RegExpUriMatcher('/https\:\/\/\w+\.com\/\d+-\d+\?param=\d+-\d+/m');
$request = static::getTestRequest();
self::assertFalse($matcher->matches($request));
}
public function testMatches(): void
{
$matcher = new RegExpUriMatcher('/https\:\/\/\w+\.com\/\d+-\d+\?param=\d+-\d+/m', PREG_UNMATCHED_AS_NULL);
$request = static::getTestRequest()->withUri(
static::getPsr17Factory()->createUri('https://example.com/23-900')
->withQuery('param=23-900')
);
self::assertTrue($matcher->matches($request));
}
}

View File

@ -10,6 +10,7 @@
namespace Pock\Tests;
use DOMDocument;
use Http\Message\MultipartStream\MultipartStreamBuilder;
use Pock\Enum\RequestMethod;
use Pock\Enum\RequestScheme;
use Pock\Exception\UnsupportedRequestException;
@ -23,6 +24,7 @@ use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\NetworkExceptionInterface;
use Psr\Http\Client\RequestExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Riverline\MultiPartParser\StreamedPart;
use RuntimeException;
/**
@ -579,6 +581,127 @@ EOF;
self::assertEquals($xml, $response->getBody()->getContents());
}
public function testMultipartFormDataMock(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::POST)
->matchScheme(RequestScheme::HTTPS)
->matchHost(self::TEST_HOST)
->matchMultipartFormData(function (StreamedPart $part) {
return $part->isMultiPart() &&
1 === count($part->getPartsByName('param1')) &&
1 === count($part->getPartsByName('param2')) &&
'value1' === $part->getPartsByName('param1')[0]->getBody() &&
'value2' === $part->getPartsByName('param2')[0]->getBody() &&
'text/plain' === $part->getPartsByName('param1')[0]->getHeader('Content-Type');
})->reply(200)
->withHeader('Content-Type', 'text/plain')
->withBody('ok');
$streamBuilder = (new MultipartStreamBuilder(self::getPsr17Factory()))
->addResource('param1', 'value1', ['headers' => ['Content-Type' => 'text/plain']])
->addResource('param2', 'value2');
$response = $builder->getClient()->sendRequest(
self::getPsr17Factory()
->createRequest(RequestMethod::POST, self::TEST_URI)
->withHeader('Content-Type', 'multipart/form-data; boundary="' . $streamBuilder->getBoundary() . '"')
->withBody($streamBuilder->build())
);
self::assertEquals(200, $response->getStatusCode());
self::assertEquals(['Content-Type' => ['text/plain']], $response->getHeaders());
self::assertEquals('ok', $response->getBody()->getContents());
}
public function testMatchBodyRegExp(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchUri(self::TEST_URI)
->matchBodyRegExp('/\d+-\d+/')
->reply(200);
$response = $builder->getClient()->sendRequest(static::getRequestWithBody('test matchable 23-900'));
self::assertEquals(200, $response->getStatusCode());
}
public function testMatchPathRegExp(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchOrigin(self::TEST_HOST)
->matchPathRegExp('/^\/?test$/')
->reply(200);
$response = $builder->getClient()->sendRequest(
static::getTestRequest()->withUri(static::getPsr17Factory()->createUri('https://test.com/test'))
);
self::assertEquals(200, $response->getStatusCode());
}
public function testMatchQueryRegExp(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchOrigin(self::TEST_HOST)
->matchQueryRegExp('/\d+-\d+/')
->reply(200);
$response = $builder->getClient()->sendRequest(
static::getTestRequest()->withUri(
static::getPsr17Factory()->createUri(self::TEST_URI)
->withQuery('param=23-900')
)
);
self::assertEquals(200, $response->getStatusCode());
}
public function testMatchUriRegExp(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchUriRegExp('/https\:\/\/\w+\.com\/\d+-\d+\?param=\d+-\d+/')
->reply(200);
$response = $builder->getClient()->sendRequest(
static::getTestRequest()->withUri(
static::getPsr17Factory()->createUri('https://example.com/23-900')
->withQuery('param=23-900')
)
);
self::assertEquals(200, $response->getStatusCode());
}
public function testMatchFormData(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchUri(self::TEST_URI)
->matchFormData(['field2' => 'value2'])
->reply(200);
$response = $builder->getClient()->sendRequest(self::getRequestWithBody('field1=value1&field2=value2'));
self::assertEquals(200, $response->getStatusCode());
}
public function testMatchExactFormData(): void
{
$builder = new PockBuilder();
$builder->matchMethod(RequestMethod::GET)
->matchUri(self::TEST_URI)
->matchExactFormData(['field2' => 'value2'])
->reply(200);
$response = $builder->getClient()->sendRequest(self::getRequestWithBody('field2=value2'));
self::assertEquals(200, $response->getStatusCode());
}
public function testFirstExampleApiMock(): void
{
$data = [