diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index fbe0112..780da6b 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -42,8 +42,8 @@ jobs:
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- #- name: Run type checker
- # run: ./vendor/bin/psalm
+ - name: Run type checker
+ run: ./vendor/bin/psalm
- name: Run unit tests
run: ./vendor/bin/phpunit --testdox --no-coverage
diff --git a/composer.json b/composer.json
index 468f8bd..cb3817e 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,8 @@
"require-dev": {
"guzzlehttp/psr7": "^2.4",
"mockery/mockery": "^1.4.1",
- "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0"
+ "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0",
+ "vimeo/psalm": "^5.7.7"
},
"conflict": {
"phpunit/phpunit": "<8.0 || >= 11.0"
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..bb222f1
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Constraint/BodyMatchesConstraint.php b/src/Constraint/BodyMatchesConstraint.php
index 9a724fe..82d32e9 100644
--- a/src/Constraint/BodyMatchesConstraint.php
+++ b/src/Constraint/BodyMatchesConstraint.php
@@ -9,7 +9,7 @@ class BodyMatchesConstraint extends Constraint
{
/** @var Constraint */
- private $constraint;
+ private Constraint $constraint;
public function __construct(Constraint $constraint)
{
@@ -23,10 +23,11 @@ public function __construct(Constraint $constraint)
*/
public function toString(): string
{
+ /** @psalm-suppress InternalMethod */
return 'message body matches ' . $this->constraint->toString();
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (!$other instanceof MessageInterface) {
return false;
@@ -34,6 +35,6 @@ protected function matches($other): bool
$other->getBody()->rewind();
$body = $other->getBody()->getContents();
- return $this->constraint->evaluate($body, '', true);
+ return (bool)$this->constraint->evaluate($body, '', true);
}
}
diff --git a/src/Constraint/HasHeaderConstraint.php b/src/Constraint/HasHeaderConstraint.php
index 0205388..74521a1 100644
--- a/src/Constraint/HasHeaderConstraint.php
+++ b/src/Constraint/HasHeaderConstraint.php
@@ -9,13 +9,10 @@
class HasHeaderConstraint extends Constraint
{
- /** @var string */
- private $name;
+ private string $name;
+ private Constraint $constraint;
- /** @var Constraint */
- private $constraint;
-
- public function __construct(string $name, $constraint = null)
+ public function __construct(string $name, Constraint|string|int $constraint = null)
{
if ($constraint === null) {
$constraint = Assert::logicalNot(Assert::isEmpty());
@@ -34,10 +31,11 @@ public function __construct(string $name, $constraint = null)
*/
public function toString(): string
{
+ /** @psalm-suppress InternalMethod */
return "has header '{$this->name}' that {$this->constraint->toString()}";
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (!$other instanceof MessageInterface) {
return false;
diff --git a/src/Constraint/HasMethodConstraint.php b/src/Constraint/HasMethodConstraint.php
index 77c736c..00a1653 100644
--- a/src/Constraint/HasMethodConstraint.php
+++ b/src/Constraint/HasMethodConstraint.php
@@ -8,8 +8,7 @@
class HasMethodConstraint extends Constraint
{
- /** @var string */
- private $method;
+ private string $method;
public function __construct(string $method)
{
@@ -26,7 +25,7 @@ public function toString(): string
return "has request method {$this->method}";
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (!$other instanceof RequestInterface) {
return false;
diff --git a/src/Constraint/HasQueryParameterConstraint.php b/src/Constraint/HasQueryParameterConstraint.php
index f4485a7..31a6459 100644
--- a/src/Constraint/HasQueryParameterConstraint.php
+++ b/src/Constraint/HasQueryParameterConstraint.php
@@ -8,15 +8,14 @@
class HasQueryParameterConstraint extends Constraint
{
- /** @var UrlEncodedMatches */
- private $inner;
+ private UrlEncodedMatches $inner;
- public function __construct($nameMatcher, $valueMatcher = null)
+ public function __construct(Constraint|string $nameMatcher, Constraint|string|null $valueMatcher = null)
{
$this->inner = new UrlEncodedMatches($nameMatcher, $valueMatcher);
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (is_string($other)) {
return $this->matchesString($other);
@@ -51,7 +50,7 @@ private function matchesString(string $other): bool
private function matchesQueryString(string $query): bool
{
- return $this->inner->evaluate($query, "", true);
+ return (bool)$this->inner->evaluate($query, "", true);
}
diff --git a/src/Constraint/HasQueryParametersConstraint.php b/src/Constraint/HasQueryParametersConstraint.php
index b177fad..32c1a19 100644
--- a/src/Constraint/HasQueryParametersConstraint.php
+++ b/src/Constraint/HasQueryParametersConstraint.php
@@ -6,8 +6,11 @@
class HasQueryParametersConstraint extends Constraint
{
/** @var HasQueryParameterConstraint[] */
- private $constraints = [];
+ private array $constraints = [];
+ /**
+ * @param array $constraints
+ */
public function __construct(array $constraints)
{
foreach ($constraints as $key => $value) {
@@ -15,7 +18,7 @@ public function __construct(array $constraints)
}
}
- public function matches($other): bool
+ public function matches(mixed $other): bool
{
foreach ($this->constraints as $constraint) {
if (!$constraint->evaluate($other, "", true)) {
diff --git a/src/Constraint/HasStatusConstraint.php b/src/Constraint/HasStatusConstraint.php
index 7848173..f1da7b9 100644
--- a/src/Constraint/HasStatusConstraint.php
+++ b/src/Constraint/HasStatusConstraint.php
@@ -9,10 +9,9 @@
class HasStatusConstraint extends Constraint
{
- /** @var Constraint */
- private $status;
+ private Constraint $status;
- public function __construct($status)
+ public function __construct(mixed $status)
{
if (!$status instanceof Constraint) {
$status = Assert::equalTo($status);
@@ -28,19 +27,20 @@ public function __construct($status)
*/
public function toString(): string
{
+ /** @psalm-suppress InternalMethod */
return "response status {$this->status->toString()}";
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (!$other instanceof ResponseInterface) {
return false;
}
- return $this->status->evaluate($other->getStatusCode(), '', true);
+ return (bool)$this->status->evaluate($other->getStatusCode(), '', true);
}
- protected function additionalFailureDescription($other): string
+ protected function additionalFailureDescription(mixed $other): string
{
if ($other instanceof ResponseInterface) {
return 'Actual status is ' . $other->getStatusCode() . ' and the body contains: ' . $other->getBody();
diff --git a/src/Constraint/HasUriConstraint.php b/src/Constraint/HasUriConstraint.php
index 28d09ea..7c3e14f 100644
--- a/src/Constraint/HasUriConstraint.php
+++ b/src/Constraint/HasUriConstraint.php
@@ -8,8 +8,7 @@
class HasUriConstraint extends Constraint
{
- /** @var string */
- private $uri;
+ private string $uri;
public function __construct(string $uri)
{
@@ -26,7 +25,7 @@ public function toString(): string
return "has request URI '{$this->uri}'";
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
if (!$other instanceof RequestInterface) {
return false;
diff --git a/src/Constraint/IsAbsoluteUriConstraint.php b/src/Constraint/IsAbsoluteUriConstraint.php
index f095a0b..9407012 100644
--- a/src/Constraint/IsAbsoluteUriConstraint.php
+++ b/src/Constraint/IsAbsoluteUriConstraint.php
@@ -11,8 +11,12 @@ public function toString(): string
return "is valid URI";
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
+ if (!is_string($other)) {
+ return false;
+ }
+
$parts = parse_url($other);
if ($parts === false) {
return false;
@@ -26,6 +30,6 @@ protected function matches($other): bool
return false;
}
- return $parts !== false;
+ return true;
}
}
\ No newline at end of file
diff --git a/src/Constraint/UrlEncodedMatches.php b/src/Constraint/UrlEncodedMatches.php
index 4cf1403..0ce4eb6 100644
--- a/src/Constraint/UrlEncodedMatches.php
+++ b/src/Constraint/UrlEncodedMatches.php
@@ -7,10 +7,10 @@
class UrlEncodedMatches extends Constraint
{
- private $nameMatcher;
- private $valueMatcher;
+ private Constraint $nameMatcher;
+ private Constraint $valueMatcher;
- public function __construct($nameMatcher, $valueMatcher = null)
+ public function __construct(Constraint|string $nameMatcher, Constraint|string|null $valueMatcher = null)
{
if (!($nameMatcher instanceof Constraint)) {
$nameMatcher = new IsEqual($nameMatcher);
@@ -26,10 +26,15 @@ public function __construct($nameMatcher, $valueMatcher = null)
$this->valueMatcher = $valueMatcher;
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
+ if (!is_string($other)) {
+ return false;
+ }
+
parse_str($other, $parsedQuery);
+ /** @var array $parsedQuery */
foreach ($parsedQuery as $key => $value) {
$nameMatches = $this->nameMatcher->evaluate($key, "", true);
$valueMatches = $this->valueMatcher->evaluate($value, "", true);
@@ -44,6 +49,7 @@ protected function matches($other): bool
public function toString(): string
{
+ /** @psalm-suppress InternalMethod */
return 'contains a name matching ' . $this->nameMatcher->toString() . ' and value matching ' . $this->valueMatcher->toString();
}
diff --git a/src/Constraint/UrlEncodedMatchesMany.php b/src/Constraint/UrlEncodedMatchesMany.php
index 9fef96c..54b0c60 100644
--- a/src/Constraint/UrlEncodedMatchesMany.php
+++ b/src/Constraint/UrlEncodedMatchesMany.php
@@ -6,8 +6,11 @@
class UrlEncodedMatchesMany extends Constraint
{
/** @var UrlEncodedMatches[] */
- private $constraints = [];
+ private array $constraints = [];
+ /**
+ * @param array $constraints
+ */
public function __construct(array $constraints)
{
foreach ($constraints as $key => $value) {
@@ -15,7 +18,7 @@ public function __construct(array $constraints)
}
}
- protected function matches($other): bool
+ protected function matches(mixed $other): bool
{
foreach ($this->constraints as $constraint) {
if (!$constraint->evaluate($other, "", true)) {
@@ -29,7 +32,7 @@ protected function matches($other): bool
public function toString(): string
{
- return join(" and ", array_map(function(HasQueryParameterConstraint $c) {
+ return join(" and ", array_map(function(UrlEncodedMatches $c) {
return $c->toString();
}, $this->constraints));
}
diff --git a/src/Functions.php b/src/Functions.php
index c033b59..d2e8cbd 100644
--- a/src/Functions.php
+++ b/src/Functions.php
@@ -4,6 +4,7 @@
use Helmich\JsonAssert\Constraint\JsonValueMatchesMany;
use Helmich\Psr7Assert\Constraint\BodyMatchesConstraint;
use Helmich\Psr7Assert\Constraint\HasHeaderConstraint;
+use Helmich\Psr7Assert\Constraint\HasQueryParameterConstraint;
use Helmich\Psr7Assert\Constraint\HasUriConstraint;
use Helmich\Psr7Assert\Constraint\IsAbsoluteUriConstraint;
use Helmich\Psr7Assert\Psr7AssertionsClass;
@@ -15,26 +16,34 @@ function hasUri(string $uri): HasUriConstraint
return new HasUriConstraint($uri);
}
-function hasHeader(string $name, $constraint = null): HasHeaderConstraint
+function hasHeader(string $name, Constraint|string|int $constraint = null): HasHeaderConstraint
{
return new HasHeaderConstraint($name, $constraint);
}
+/**
+ * @param array $constraints
+ * @return Constraint
+ */
function hasHeaders(array $constraints): Constraint
{
return Psr7AssertionsClass::hasHeaders($constraints);
}
-function hasStatus($status): Constraint
+function hasStatus(Constraint|int $status): Constraint
{
return Psr7AssertionsClass::hasStatus($status);
}
-function hasQueryParameter($name, $value = null): Constraint
+function hasQueryParameter(Constraint|string $name, Constraint|string $value = null): Constraint
{
return Psr7AssertionsClass::hasQueryParameter($name, $value);
}
+/**
+ * @param array $constraints
+ * @return Constraint
+ */
function hasQueryParameters(array $constraints): Constraint
{
return Psr7AssertionsClass::hasQueryParameters($constraints);
@@ -93,12 +102,12 @@ function isDelete(): Constraint
return Psr7AssertionsClass::isDelete();
}
-function bodyMatches($constraint): Constraint
+function bodyMatches(Constraint $constraint): Constraint
{
return new BodyMatchesConstraint($constraint);
}
-function bodyMatchesJson($constraints): Constraint
+function bodyMatchesJson(array $constraints): Constraint
{
return Assert::logicalAnd(
hasContentType('application/json'),
@@ -111,6 +120,10 @@ function bodyMatchesJson($constraints): Constraint
);
}
+/**
+ * @param array $constraints
+ * @return Constraint
+ */
function bodyMatchesForm(array $constraints): Constraint
{
return Psr7AssertionsClass::bodyMatchesForm($constraints);
diff --git a/src/Psr7Assertions.php b/src/Psr7Assertions.php
index 43349cb..ba2f267 100644
--- a/src/Psr7Assertions.php
+++ b/src/Psr7Assertions.php
@@ -28,17 +28,22 @@ public static function assertRequestHasUri(RequestInterface $request, string $ur
Assert::assertThat($request, static::hasUri($uri));
}
- public static function assertMessageHasHeader(MessageInterface $message, string $headerName, $headerValue = null): void
+ public static function assertMessageHasHeader(MessageInterface $message, string $headerName, Constraint|string $headerValue = null): void
{
Assert::assertThat($message, static::hasHeader($headerName, $headerValue));
}
+ /**
+ * @param MessageInterface $message
+ * @param array $constraints
+ * @return void
+ */
public static function assertMessageHasHeaders(MessageInterface $message, array $constraints): void
{
Assert::assertThat($message, static::hasHeaders($constraints));
}
- public static function assertMessageBodyMatches(MessageInterface $message, $constraint): void
+ public static function assertMessageBodyMatches(MessageInterface $message, Constraint $constraint): void
{
Assert::assertThat($message, static::bodyMatches($constraint));
}
@@ -48,6 +53,11 @@ public static function assertMessageBodyMatchesJson(MessageInterface $message, a
Assert::assertThat($message, static::bodyMatchesJson($jsonConstraints));
}
+ /**
+ * @param MessageInterface $message
+ * @param array $formConstraints
+ * @return void
+ */
public static function assertMessageBodyMatchesForm(MessageInterface $message, array $formConstraints): void
{
Assert::assertThat($message, static::bodyMatchesForm($formConstraints));
@@ -103,25 +113,22 @@ public static function assertRequestIsDelete(RequestInterface $request): void
Assert::assertThat($request, static::isDelete());
}
- /**
- * @param string $uri
- */
public static function assertStringIsAbsoluteUri(string $uri): void
{
Assert::assertThat($uri, static::isAbsoluteUri());
}
- /**
- * @param string|UriInterface|RequestInterface $uriOrRequest
- * @param string|Constraint $name
- * @param string|Constraint|null $value
- */
- public static function assertHasQueryParameter($uriOrRequest, $name, $value = null): void
+ public static function assertHasQueryParameter(string|UriInterface|RequestInterface $uriOrRequest, string|Constraint $name, string|Constraint|null $value = null): void
{
Assert::assertThat($uriOrRequest, static::hasQueryParameter($name, $value));
}
- public static function assertHasQueryParameters($uriOrRequest, array $parameters): void
+ /**
+ * @param string|UriInterface|RequestInterface $uriOrRequest
+ * @param array $parameters
+ * @return void
+ */
+ public static function assertHasQueryParameters(string|UriInterface|RequestInterface $uriOrRequest, array $parameters): void
{
Assert::assertThat($uriOrRequest, static::hasQueryParameters($parameters));
}
@@ -136,7 +143,7 @@ public static function hasMethod(string $method): Constraint
return new HasMethodConstraint($method);
}
- public static function hasStatus($status): Constraint
+ public static function hasStatus(Constraint|int $status): Constraint
{
return new HasStatusConstraint($status);
}
@@ -181,11 +188,15 @@ public static function isDelete(): Constraint
return static::hasMethod('DELETE');
}
- public static function hasHeader(string $name, $constraint = null): Constraint
+ public static function hasHeader(string $name, Constraint|string|int $constraint = null): Constraint
{
return new HasHeaderConstraint($name, $constraint);
}
+ /**
+ * @param array $constraints
+ * @return Constraint
+ */
public static function hasHeaders(array $constraints): Constraint
{
$headerConstraints = [];
@@ -206,16 +217,15 @@ public static function bodyMatches(Constraint $constraint): Constraint
return new BodyMatchesConstraint($constraint);
}
- /**
- * @param string|Constraint $name
- * @param string|Constraint|null $value
- * @return Constraint
- */
- public static function hasQueryParameter($name, $value = null): Constraint
+ public static function hasQueryParameter(string|Constraint $name, string|Constraint|null $value = null): Constraint
{
return new HasQueryParameterConstraint($name, $value);
}
+ /**
+ * @param array $parameters
+ * @return Constraint
+ */
public static function hasQueryParameters(array $parameters): Constraint
{
return new HasQueryParametersConstraint($parameters);
@@ -234,6 +244,10 @@ public static function bodyMatchesJson(array $constraints): Constraint
);
}
+ /**
+ * @param array $constraints
+ * @return Constraint
+ */
public static function bodyMatchesForm(array $constraints): Constraint
{
return Assert::logicalAnd(
@@ -242,9 +256,6 @@ public static function bodyMatchesForm(array $constraints): Constraint
);
}
- /**
- * @return Constraint
- */
public static function isAbsoluteUri(): Constraint
{
return new IsAbsoluteUriConstraint();