mirror of
https://github.com/Neur0toxine/pock.git
synced 2024-11-28 15:56:09 +03:00
better xml matcher, refactor comparators
This commit is contained in:
parent
b08ba6f6cd
commit
e352c310d7
@ -47,7 +47,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-mock/php-mock": "^2.3"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-client-implementation": "1.0",
|
||||
|
29
src/Comparator/ComparatorInterface.php
Normal file
29
src/Comparator/ComparatorInterface.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category ComparatorInterface
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
/**
|
||||
* Interface ComparatorInterface
|
||||
*
|
||||
* @category ComparatorInterface
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
interface ComparatorInterface
|
||||
{
|
||||
/**
|
||||
* Compare two values.
|
||||
*
|
||||
* @param mixed $first
|
||||
* @param mixed $second
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function compare($first, $second): bool;
|
||||
}
|
44
src/Comparator/ComparatorLocator.php
Normal file
44
src/Comparator/ComparatorLocator.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category ComparatorLocator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ComparatorLocator
|
||||
*
|
||||
* @category ComparatorLocator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
class ComparatorLocator
|
||||
{
|
||||
/** @var \Pock\Comparator\ComparatorInterface[] */
|
||||
private static $comparators = [];
|
||||
|
||||
/**
|
||||
* Returns comparator.
|
||||
*
|
||||
* @param string $fqn
|
||||
*
|
||||
* @return \Pock\Comparator\ComparatorInterface
|
||||
*/
|
||||
public static function get(string $fqn): ComparatorInterface
|
||||
{
|
||||
if (!class_exists($fqn)) {
|
||||
throw new RuntimeException('Comparator ' . $fqn . ' does not exist.');
|
||||
}
|
||||
|
||||
if (!array_key_exists($fqn, static::$comparators)) {
|
||||
static::$comparators[$fqn] = new $fqn();
|
||||
}
|
||||
|
||||
return static::$comparators[$fqn];
|
||||
}
|
||||
}
|
53
src/Comparator/LtrScalarArrayComparator.php
Normal file
53
src/Comparator/LtrScalarArrayComparator.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category LtrScalarArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
/**
|
||||
* Class LtrScalarArrayComparator
|
||||
*
|
||||
* @category LtrScalarArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
class LtrScalarArrayComparator implements ComparatorInterface
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function compare($first, $second): bool
|
||||
{
|
||||
if (!is_array($first) || !is_array($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::isNeedlePresentInHaystack($first, $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needle values is present in haystack.
|
||||
* Doesn't work for multidimensional arrays.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $needle
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $haystack
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isNeedlePresentInHaystack(array $needle, array $haystack): bool
|
||||
{
|
||||
foreach ($needle as $value) {
|
||||
if (!in_array($value, $haystack, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
64
src/Comparator/RecursiveArrayComparator.php
Normal file
64
src/Comparator/RecursiveArrayComparator.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category RecursiveArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
/**
|
||||
* Class RecursiveArrayComparator
|
||||
*
|
||||
* @category RecursiveArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
class RecursiveArrayComparator implements ComparatorInterface
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function compare($first, $second): bool
|
||||
{
|
||||
if (!is_array($first) || !is_array($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::recursiveCompareArrays($first, $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if both arrays are equal recursively.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $first
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $second
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function recursiveCompareArrays(array $first, array $second): bool
|
||||
{
|
||||
if (count($first) !== count($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty(array_diff(array_keys($first), array_keys($second)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($first as $key => $value) {
|
||||
if (is_array($value) && !self::recursiveCompareArrays($value, $second[$key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($value !== $second[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
61
src/Comparator/RecursiveLtrArrayComparator.php
Normal file
61
src/Comparator/RecursiveLtrArrayComparator.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category RecursiveLtrArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
/**
|
||||
* Class RecursiveLtrArrayComparator
|
||||
*
|
||||
* @category RecursiveLtrArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
class RecursiveLtrArrayComparator extends RecursiveArrayComparator
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function compare($first, $second): bool
|
||||
{
|
||||
if (!is_array($first) || !is_array($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::recursiveNeedlePresentInHaystack($first, $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needle values is present in haystack.
|
||||
* Works for multidimensional arrays. Internal arrays will be treated as values (e.g. will be compared recursively).
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $needle
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $haystack
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function recursiveNeedlePresentInHaystack(array $needle, array $haystack): bool
|
||||
{
|
||||
if (!empty(array_diff(array_keys($needle), array_keys($haystack)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($needle as $key => $value) {
|
||||
if (is_array($value) && !self::recursiveCompareArrays($value, $haystack[$key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($value !== $haystack[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
47
src/Comparator/ScalarFlatArrayComparator.php
Normal file
47
src/Comparator/ScalarFlatArrayComparator.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category ScalarFlatArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Comparator;
|
||||
|
||||
/**
|
||||
* Class ScalarFlatArrayComparator
|
||||
*
|
||||
* @category ScalarFlatArrayComparator
|
||||
* @package Pock\Comparator
|
||||
*/
|
||||
class ScalarFlatArrayComparator implements ComparatorInterface
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function compare($first, $second): bool
|
||||
{
|
||||
if (!is_array($first) || !is_array($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::compareScalarFlatArrays($first, $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if two one-dimensional string arrays are equal.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $first
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $second
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function compareScalarFlatArrays(array $first, array $second): bool
|
||||
{
|
||||
return count($first) === count($second) &&
|
||||
array_diff($first, $second) === array_diff($second, $first);
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.1
|
||||
*
|
||||
* @category AbstractArrayPoweredComponent
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
/**
|
||||
* Class AbstractArrayPoweredComponent
|
||||
*
|
||||
* @category AbstractArrayPoweredComponent
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
abstract class AbstractArrayPoweredComponent
|
||||
{
|
||||
/**
|
||||
* Returns true if both arrays are equal recursively.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $first
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $second
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function recursiveCompareArrays(array $first, array $second): bool
|
||||
{
|
||||
if (count($first) !== count($second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty(array_diff(array_keys($first), array_keys($second)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($first as $key => $value) {
|
||||
if (is_array($value) && !self::recursiveCompareArrays($value, $second[$key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($value !== $second[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if two one-dimensional string arrays are equal.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $first
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $second
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function compareStringArrays(array $first, array $second): bool
|
||||
{
|
||||
return count($first) === count($second) &&
|
||||
array_diff($first, $second) === array_diff($second, $first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needle values is present in haystack.
|
||||
* Doesn't work for multidimensional arrays.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $needle
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $haystack
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isNeedlePresentInHaystack(array $needle, array $haystack): bool
|
||||
{
|
||||
foreach ($needle as $value) {
|
||||
if (!in_array($value, $haystack, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needle values is present in haystack.
|
||||
* Works for multidimensional arrays. Internal arrays will be treated as values (e.g. will be compared recursively).
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $needle
|
||||
* @phpstan-ignore-next-line
|
||||
* @param array $haystack
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function recursiveNeedlePresentInHaystack(array $needle, array $haystack): bool
|
||||
{
|
||||
if (!empty(array_diff(array_keys($needle), array_keys($haystack)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($needle as $key => $value) {
|
||||
if (is_array($value) && !self::recursiveCompareArrays($value, $haystack[$key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($value !== $haystack[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\RecursiveArrayComparator;
|
||||
use Pock\Traits\SeekableStreamDataExtractor;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
@ -18,7 +20,7 @@ use Psr\Http\Message\RequestInterface;
|
||||
* @category AbstractSerializedBodyMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
abstract class AbstractSerializedBodyMatcher extends AbstractArrayPoweredComponent implements RequestMatcherInterface
|
||||
abstract class AbstractSerializedBodyMatcher implements RequestMatcherInterface
|
||||
{
|
||||
use SeekableStreamDataExtractor;
|
||||
|
||||
@ -54,7 +56,7 @@ abstract class AbstractSerializedBodyMatcher extends AbstractArrayPoweredCompone
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::recursiveCompareArrays($bodyData, $this->data);
|
||||
return ComparatorLocator::get(RecursiveArrayComparator::class)->compare($bodyData, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,17 +33,7 @@ class BodyMatcher implements RequestMatcherInterface
|
||||
*/
|
||||
public function __construct($contents)
|
||||
{
|
||||
if (is_string($contents)) {
|
||||
$this->contents = $contents;
|
||||
}
|
||||
|
||||
if ($contents instanceof StreamInterface) {
|
||||
$this->contents = static::getStreamData($contents);
|
||||
}
|
||||
|
||||
if (is_resource($contents)) {
|
||||
$this->contents = static::readAllResource($contents);
|
||||
}
|
||||
$this->contents = static::getEntryItemData($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,4 +60,24 @@ class BodyMatcher implements RequestMatcherInterface
|
||||
fseek($resource, 0);
|
||||
return (string) stream_get_contents($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StreamInterface|resource|string $contents
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getEntryItemData($contents): string
|
||||
{
|
||||
if (is_string($contents)) {
|
||||
return $contents;
|
||||
}
|
||||
|
||||
if ($contents instanceof StreamInterface) {
|
||||
return static::getStreamData($contents);
|
||||
}
|
||||
|
||||
if (is_resource($contents)) {
|
||||
return static::readAllResource($contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\ScalarFlatArrayComparator;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@ -28,6 +30,7 @@ class ExactHeaderMatcher extends HeaderMatcher
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::compareStringArrays($request->getHeader($this->header), $this->value);
|
||||
return ComparatorLocator::get(ScalarFlatArrayComparator::class)
|
||||
->compare($request->getHeader($this->header), $this->value);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\RecursiveArrayComparator;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@ -30,6 +32,6 @@ class ExactQueryMatcher extends QueryMatcher
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::recursiveCompareArrays($this->query, $query);
|
||||
return ComparatorLocator::get(RecursiveArrayComparator::class)->compare($this->query, $query);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\LtrScalarArrayComparator;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@ -17,7 +19,7 @@ use Psr\Http\Message\RequestInterface;
|
||||
* @category HeaderMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
class HeaderMatcher extends AbstractArrayPoweredComponent implements RequestMatcherInterface
|
||||
class HeaderMatcher implements RequestMatcherInterface
|
||||
{
|
||||
/** @var string */
|
||||
protected $header;
|
||||
@ -51,6 +53,7 @@ class HeaderMatcher extends AbstractArrayPoweredComponent implements RequestMatc
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::isNeedlePresentInHaystack($this->value, $request->getHeader($this->header));
|
||||
return ComparatorLocator::get(LtrScalarArrayComparator::class)
|
||||
->compare($this->value, $request->getHeader($this->header));
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\LtrScalarArrayComparator;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@ -17,7 +19,7 @@ use Psr\Http\Message\RequestInterface;
|
||||
* @category HeadersMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
class HeadersMatcher extends AbstractArrayPoweredComponent implements RequestMatcherInterface
|
||||
class HeadersMatcher implements RequestMatcherInterface
|
||||
{
|
||||
/** @var array<string, string|string[]> */
|
||||
protected $headers;
|
||||
@ -48,7 +50,7 @@ class HeadersMatcher extends AbstractArrayPoweredComponent implements RequestMat
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
if (!static::isNeedlePresentInHaystack($value, $request->getHeader($name))) {
|
||||
if (!ComparatorLocator::get(LtrScalarArrayComparator::class)->compare($value, $request->getHeader($name))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,9 @@
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\RecursiveLtrArrayComparator;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Class QueryMatcher
|
||||
@ -18,7 +19,7 @@ use Psr\Http\Message\UriInterface;
|
||||
* @category QueryMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
class QueryMatcher extends AbstractArrayPoweredComponent implements RequestMatcherInterface
|
||||
class QueryMatcher implements RequestMatcherInterface
|
||||
{
|
||||
/** @var array<string, mixed> */
|
||||
protected $query;
|
||||
@ -44,7 +45,7 @@ class QueryMatcher extends AbstractArrayPoweredComponent implements RequestMatch
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::recursiveNeedlePresentInHaystack($this->query, $query);
|
||||
return ComparatorLocator::get(RecursiveLtrArrayComparator::class)->compare($this->query, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
194
src/Matchers/XmlBodyMatcher.php
Normal file
194
src/Matchers/XmlBodyMatcher.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category XmlBodyMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
|
||||
namespace Pock\Matchers;
|
||||
|
||||
use DOMDocument;
|
||||
use Pock\Exception\XmlException;
|
||||
use Throwable;
|
||||
use XSLTProcessor;
|
||||
use Pock\Traits\SeekableStreamDataExtractor;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class XmlBodyMatcher
|
||||
*
|
||||
* @category XmlBodyMatcher
|
||||
* @package Pock\Matchers
|
||||
*/
|
||||
class XmlBodyMatcher extends BodyMatcher
|
||||
{
|
||||
use SeekableStreamDataExtractor;
|
||||
|
||||
private const TAG_SORT_XSLT = <<<EOT
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output omit-xml-declaration="yes" indent="yes"/>
|
||||
<xsl:strip-space elements="*"/>
|
||||
<xsl:template match="node()|@*">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*">
|
||||
<xsl:sort select="name()"/>
|
||||
</xsl:apply-templates>
|
||||
<xsl:apply-templates select="node()">
|
||||
<xsl:sort select="name()"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
EOT;
|
||||
|
||||
/** @var XSLTProcessor|null */
|
||||
private static $sorter;
|
||||
|
||||
/** @var bool */
|
||||
private $useFallback;
|
||||
|
||||
/**
|
||||
* XmlBodyMatcher constructor.
|
||||
*
|
||||
* @param DOMDocument|\Psr\Http\Message\StreamInterface|resource|string $referenceXml
|
||||
*
|
||||
* @throws \Pock\Exception\XmlException
|
||||
*/
|
||||
public function __construct($referenceXml)
|
||||
{
|
||||
if (!extension_loaded('xsl') || !extension_loaded('dom')) {
|
||||
$this->useFallback = true;
|
||||
}
|
||||
|
||||
if (!extension_loaded('xsl')) {
|
||||
$this->useFallback = true;
|
||||
|
||||
if (extension_loaded('dom') && $referenceXml instanceof DOMDocument) {
|
||||
$referenceXml = static::getDOMString($referenceXml);
|
||||
}
|
||||
|
||||
parent::__construct($referenceXml); // @phpstan-ignore-line
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($referenceXml instanceof DOMDocument) {
|
||||
parent::__construct(static::sortXmlTags($referenceXml));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct(static::sortXmlTags(
|
||||
static::createDOMDocument(static::getEntryItemData($referenceXml))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function matches(RequestInterface $request): bool
|
||||
{
|
||||
if ($this->useFallback) {
|
||||
return parent::matches($request);
|
||||
}
|
||||
|
||||
if (0 === $request->getBody()->getSize()) {
|
||||
return '' === $this->contents;
|
||||
}
|
||||
|
||||
return self::sortXmlTags(self::createDOMDocument(self::getStreamData($request->getBody()))) === $this->contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new document with tags sorted alphabetically.
|
||||
*
|
||||
* @param \DOMDocument $document
|
||||
*
|
||||
* @return string
|
||||
* @throws \RuntimeException|\Pock\Exception\XmlException
|
||||
*/
|
||||
private static function sortXmlTags(DOMDocument $document): string
|
||||
{
|
||||
$xml = static::getSorter()->transformToXml($document);
|
||||
|
||||
if (false === $xml) {
|
||||
throw new RuntimeException('Cannot sort XML nodes');
|
||||
}
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns XSLTProcessor with XSLT which sorts tags alphabetically.
|
||||
*
|
||||
* @return \XSLTProcessor
|
||||
* @throws \Pock\Exception\XmlException
|
||||
*/
|
||||
private static function getSorter(): XSLTProcessor
|
||||
{
|
||||
if (null === static::$sorter) {
|
||||
static::$sorter = new XSLTProcessor();
|
||||
static::$sorter->importStylesheet(static::createDOMDocument(static::TAG_SORT_XSLT));
|
||||
}
|
||||
|
||||
return static::$sorter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DOMDocument with provided XML string.
|
||||
*
|
||||
* @param string $xml
|
||||
* @param string $version
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return \DOMDocument
|
||||
* @throws \Pock\Exception\XmlException
|
||||
*/
|
||||
private static function createDOMDocument(string $xml, string $version = '1.0', string $encoding = ''): DOMDocument
|
||||
{
|
||||
if ('' === $xml) {
|
||||
throw new XmlException('XML must not be empty.');
|
||||
}
|
||||
|
||||
$error = null;
|
||||
$document = new DOMDocument($version, $encoding);
|
||||
|
||||
try {
|
||||
set_error_handler(static function ($code, $message) {
|
||||
throw new XmlException($message, $code);
|
||||
});
|
||||
$document->loadXML(trim($xml));
|
||||
} catch (XmlException $exception) {
|
||||
$error = $exception;
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
if (null !== $error) {
|
||||
throw $error;
|
||||
}
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMDocument $document
|
||||
*
|
||||
* @return string
|
||||
* @throws \Pock\Exception\XmlException
|
||||
*/
|
||||
private static function getDOMString(DOMDocument $document): string
|
||||
{
|
||||
$result = $document->saveXML();
|
||||
|
||||
if (false === $result) {
|
||||
throw new XmlException('Cannot export XML.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -10,11 +10,13 @@
|
||||
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;
|
||||
@ -36,6 +38,7 @@ use Pock\Matchers\QueryMatcher;
|
||||
use Pock\Matchers\RequestMatcherInterface;
|
||||
use Pock\Matchers\SchemeMatcher;
|
||||
use Pock\Matchers\UriMatcher;
|
||||
use Pock\Matchers\XmlBodyMatcher;
|
||||
use Pock\Traits\JsonDecoderTrait;
|
||||
use Pock\Traits\JsonSerializerAwareTrait;
|
||||
use Pock\Traits\XmlSerializerAwareTrait;
|
||||
@ -286,21 +289,38 @@ class PockBuilder
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Match XML request body using raw XML data.
|
||||
*
|
||||
* **Note:** this method will fallback to the string comparison if ext-xsl is not available.
|
||||
* It also doesn't serializer values with available XML serializer.
|
||||
* Use PockBuilder::matchSerializedXmlBody if you want to execute available serializer.
|
||||
*
|
||||
* @see \Pock\PockBuilder::matchSerializedXmlBody()
|
||||
*
|
||||
* @param DOMDocument|\Psr\Http\Message\StreamInterface|resource|string $data
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function matchXmlBody($data): self
|
||||
{
|
||||
return $this->addMatcher(new XmlBodyMatcher($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Match XML request body.
|
||||
*
|
||||
* **Note:** this method will use string comparison for now. It'll be improved in future.
|
||||
* This method will try to use available XML serializer before matching.
|
||||
*
|
||||
* @todo Don't use simple string comparison. Match the entire body by its DOM.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @phpstan-ignore-next-line
|
||||
* @param string|array|object $data
|
||||
*
|
||||
* @return self
|
||||
* @throws \Pock\Exception\XmlException
|
||||
*/
|
||||
public function matchXmlBody($data): self
|
||||
public function matchSerializedXmlBody($data): self
|
||||
{
|
||||
return $this->matchBody(self::serializeXml($data) ?? '');
|
||||
return $this->matchXmlBody(self::serializeXml($data) ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
48
tests/src/Comparator/ComparatorLocatorTest.php
Normal file
48
tests/src/Comparator/ComparatorLocatorTest.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category ComparatorLocatorTest
|
||||
* @package Pock\Tests\Comparator
|
||||
*/
|
||||
|
||||
namespace Pock\Tests\Comparator;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Pock\Comparator\ComparatorLocator;
|
||||
use Pock\Comparator\LtrScalarArrayComparator;
|
||||
use Pock\Comparator\RecursiveArrayComparator;
|
||||
use Pock\Comparator\RecursiveLtrArrayComparator;
|
||||
use Pock\Comparator\ScalarFlatArrayComparator;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ComparatorLocatorTest
|
||||
*
|
||||
* @category ComparatorLocatorTest
|
||||
* @package Pock\Tests\Comparator
|
||||
*/
|
||||
class ComparatorLocatorTest extends TestCase
|
||||
{
|
||||
public function testGetException(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('Comparator random does not exist.');
|
||||
|
||||
ComparatorLocator::get('random');
|
||||
}
|
||||
|
||||
public function testGet(): void
|
||||
{
|
||||
$comparator = ComparatorLocator::get(ScalarFlatArrayComparator::class);
|
||||
|
||||
self::assertInstanceOf(ScalarFlatArrayComparator::class, $comparator);
|
||||
self::assertTrue($comparator->compare(['1'], ['1']));
|
||||
self::assertFalse($comparator->compare(['1'], ['2']));
|
||||
self::assertFalse($comparator->compare(null, null));
|
||||
self::assertFalse(ComparatorLocator::get(LtrScalarArrayComparator::class)->compare(null, null));
|
||||
self::assertFalse(ComparatorLocator::get(RecursiveArrayComparator::class)->compare(null, null));
|
||||
self::assertFalse(ComparatorLocator::get(RecursiveLtrArrayComparator::class)->compare(null, null));
|
||||
}
|
||||
}
|
62
tests/src/Matchers/XmlBodyMatcherTest.php
Normal file
62
tests/src/Matchers/XmlBodyMatcherTest.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP 7.3
|
||||
*
|
||||
* @category XmlBodyMatcherTest
|
||||
* @package Pock\Tests\Matchers
|
||||
*/
|
||||
|
||||
namespace Pock\Tests\Matchers;
|
||||
|
||||
use Pock\Matchers\XmlBodyMatcher;
|
||||
use Pock\TestUtils\PockTestCase;
|
||||
|
||||
/**
|
||||
* Class XmlBodyMatcherTest
|
||||
*
|
||||
* @category XmlBodyMatcherTest
|
||||
* @package Pock\Tests\Matchers
|
||||
*/
|
||||
class XmlBodyMatcherTest extends PockTestCase
|
||||
{
|
||||
public function testEmptyXml(): void
|
||||
{
|
||||
$this->expectExceptionMessage('XML must not be empty.');
|
||||
new XmlBodyMatcher('');
|
||||
}
|
||||
|
||||
public function testInvalidXml(): void
|
||||
{
|
||||
$brokenXml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field><![CDATA[test]></field>
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
$this->expectExceptionMessage('DOMDocument::loadXML(): CData section not finished');
|
||||
new XmlBodyMatcher($brokenXml);
|
||||
}
|
||||
|
||||
public function testMatchXml(): void
|
||||
{
|
||||
$expected = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field key="2" id="1"><![CDATA[test]]></field>
|
||||
</result>
|
||||
EOF;
|
||||
$actual = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<result>
|
||||
<field id="1" key="2">
|
||||
<![CDATA[test]]>
|
||||
</field>
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
self::assertTrue((new XmlBodyMatcher($expected))->matches(static::getRequestWithBody($actual)));
|
||||
}
|
||||
}
|
@ -9,10 +9,11 @@
|
||||
|
||||
namespace Pock\Tests;
|
||||
|
||||
use DOMDocument;
|
||||
use phpmock\MockBuilder;
|
||||
use Pock\Enum\RequestMethod;
|
||||
use Pock\Enum\RequestScheme;
|
||||
use Pock\Exception\UnsupportedRequestException;
|
||||
use Pock\Factory\ReplyFactoryInterface;
|
||||
use Pock\PockBuilder;
|
||||
use Pock\PockResponseBuilder;
|
||||
use Pock\TestUtils\PockTestCase;
|
||||
@ -22,7 +23,6 @@ use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Client\NetworkExceptionInterface;
|
||||
use Psr\Http\Client\RequestExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
@ -85,6 +85,23 @@ class PockBuilderTest extends PockTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testThrowRequestExceptionGetRequest(): void
|
||||
{
|
||||
$builder = new PockBuilder();
|
||||
$request = self::getPsr17Factory()->createRequest(RequestMethod::GET, self::TEST_URI);
|
||||
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->throwRequestException();
|
||||
|
||||
try {
|
||||
$builder->getClient()->sendRequest($request);
|
||||
} catch (RequestExceptionInterface $exception) {
|
||||
self::assertEquals($request, $exception->getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
public function testMatchHeader(): void
|
||||
{
|
||||
$builder = new PockBuilder();
|
||||
@ -305,7 +322,124 @@ class PockBuilderTest extends PockTestCase
|
||||
], json_decode($response->getBody()->getContents(), true));
|
||||
}
|
||||
|
||||
public function testXmlResponse(): void
|
||||
public function testMatchXmlString(): void
|
||||
{
|
||||
$xml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<entry><![CDATA[Forbidden]]></entry>
|
||||
</result>
|
||||
|
||||
EOF;
|
||||
$simpleObject = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field><![CDATA[test]]></field>
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
$builder = new PockBuilder();
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->matchXmlBody($simpleObject)
|
||||
->repeat(2)
|
||||
->reply(403)
|
||||
->withHeader('Content-Type', 'text/xml')
|
||||
->withXml(['error' => 'Forbidden']);
|
||||
|
||||
$response = $builder->getClient()->sendRequest(
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream($simpleObject))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
public function testMatchXmlStream(): void
|
||||
{
|
||||
$xml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<entry><![CDATA[Forbidden]]></entry>
|
||||
</result>
|
||||
|
||||
EOF;
|
||||
$simpleObject = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field><![CDATA[test]]></field>
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
$builder = new PockBuilder();
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->matchXmlBody(self::getPsr17Factory()->createStream($simpleObject))
|
||||
->repeat(2)
|
||||
->reply(403)
|
||||
->withHeader('Content-Type', 'text/xml')
|
||||
->withXml(['error' => 'Forbidden']);
|
||||
|
||||
$response = $builder->getClient()->sendRequest(
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream($simpleObject))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
public function testMatchXmlDOMDocument(): void
|
||||
{
|
||||
$xml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<entry><![CDATA[Forbidden]]></entry>
|
||||
</result>
|
||||
|
||||
EOF;
|
||||
$simpleObject = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field><![CDATA[test]]></field>
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
$document = new DOMDocument();
|
||||
$document->loadXML($simpleObject);
|
||||
|
||||
$builder = new PockBuilder();
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->matchXmlBody($document)
|
||||
->repeat(2)
|
||||
->reply(403)
|
||||
->withHeader('Content-Type', 'text/xml')
|
||||
->withXml(['error' => 'Forbidden']);
|
||||
|
||||
$response = $builder->getClient()->sendRequest(
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream($simpleObject))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matchXmlNoXslProvider
|
||||
*/
|
||||
public function testMatchXmlNoXsl(string $simpleObject, bool $expectException): void
|
||||
{
|
||||
$xml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
@ -315,11 +449,77 @@ class PockBuilderTest extends PockTestCase
|
||||
|
||||
EOF;
|
||||
|
||||
if ($expectException) {
|
||||
$this->expectException(UnsupportedRequestException::class);
|
||||
}
|
||||
|
||||
$mock = (new MockBuilder())->setNamespace('Pock\Matchers')
|
||||
->setName('extension_loaded')
|
||||
->setFunction(
|
||||
static function (string $extension) {
|
||||
if ('xsl' === $extension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return \extension_loaded($extension);
|
||||
}
|
||||
)->build();
|
||||
$mock->enable();
|
||||
|
||||
$document = new DOMDocument();
|
||||
$document->loadXML($simpleObject);
|
||||
|
||||
$builder = new PockBuilder();
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->matchXmlBody(new SimpleObject())
|
||||
->matchXmlBody($document)
|
||||
->repeat(2)
|
||||
->reply(403)
|
||||
->withHeader('Content-Type', 'text/xml')
|
||||
->withXml(['error' => 'Forbidden']);
|
||||
|
||||
$mock->disable();
|
||||
|
||||
$response = $builder->getClient()->sendRequest(
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream($simpleObject))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
public function testSerializedXmlResponse(): void
|
||||
{
|
||||
$xml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<entry><![CDATA[Forbidden]]></entry>
|
||||
</result>
|
||||
|
||||
EOF;
|
||||
$simpleObjectFreeFormXml = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<result>
|
||||
|
||||
<field>
|
||||
<![CDATA[test]]>
|
||||
|
||||
</field>
|
||||
|
||||
</result>
|
||||
EOF;
|
||||
|
||||
$builder = new PockBuilder();
|
||||
$builder->matchMethod(RequestMethod::GET)
|
||||
->matchScheme(RequestScheme::HTTPS)
|
||||
->matchHost(self::TEST_HOST)
|
||||
->matchSerializedXmlBody(new SimpleObject())
|
||||
->repeat(2)
|
||||
->reply(403)
|
||||
->withHeader('Content-Type', 'text/xml')
|
||||
->withXml(['error' => 'Forbidden']);
|
||||
@ -328,13 +528,23 @@ EOF;
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream(
|
||||
self::getXmlSerializer()->serialize(new SimpleObject())
|
||||
PHP_EOL . self::getXmlSerializer()->serialize(new SimpleObject()) . PHP_EOL
|
||||
))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
|
||||
$response = $builder->getClient()->sendRequest(
|
||||
self::getPsr17Factory()
|
||||
->createRequest(RequestMethod::GET, self::TEST_URI)
|
||||
->withBody(self::getPsr17Factory()->createStream($simpleObjectFreeFormXml))
|
||||
);
|
||||
|
||||
self::assertEquals(403, $response->getStatusCode());
|
||||
self::assertEquals(['Content-Type' => ['text/xml']], $response->getHeaders());
|
||||
self::assertEquals($xml, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
public function testFirstExampleApiMock(): void
|
||||
@ -649,4 +859,18 @@ EOF;
|
||||
self::TEST_URI
|
||||
));
|
||||
}
|
||||
|
||||
public function matchXmlNoXslProvider(): array
|
||||
{
|
||||
$simpleObject = <<<'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<result>
|
||||
<field><![CDATA[test]]></field>
|
||||
</result>
|
||||
EOF;
|
||||
return [
|
||||
[$simpleObject, true],
|
||||
[$simpleObject . "\n", false]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,19 @@ abstract class PockTestCase extends TestCase
|
||||
return static::getPsr17Factory()->createRequest($method ?? static::TEST_METHOD, static::TEST_URI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
*
|
||||
* @return \Psr\Http\Message\RequestInterface
|
||||
*/
|
||||
protected static function getRequestWithBody(string $body): RequestInterface
|
||||
{
|
||||
return static::getPsr17Factory()->createRequest(
|
||||
RequestMethod::GET,
|
||||
static::TEST_URI
|
||||
)->withBody(self::getPsr17Factory()->createStream($body));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Nyholm\Psr7\Factory\Psr17Factory
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user