├── LICENSE.txt ├── composer.json └── src ├── Constraint ├── BodyMatchesConstraint.php ├── HasHeaderConstraint.php ├── HasMethodConstraint.php ├── HasQueryParameterConstraint.php ├── HasQueryParametersConstraint.php ├── HasStatusConstraint.php ├── HasUriConstraint.php ├── IsAbsoluteUriConstraint.php ├── UrlEncodedMatches.php └── UrlEncodedMatchesMany.php ├── Functions.php ├── Psr7Assertions.php └── Psr7AssertionsClass.php /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Martin Helmich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helmich/phpunit-psr7-assert", 3 | "description": "PHPUnit assertions for testing PSR7-compliant applications", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Martin Helmich", 8 | "email": "m.helmich@mittwald.de" 9 | } 10 | ], 11 | "require": { 12 | "php": "^8.0", 13 | "helmich/phpunit-json-assert": "^3.4", 14 | "psr/http-message": "^1.1 || ^2.0" 15 | }, 16 | "require-dev": { 17 | "guzzlehttp/psr7": "^2.4", 18 | "mockery/mockery": "^1.4.1", 19 | "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0" 20 | }, 21 | "conflict": { 22 | "phpunit/phpunit": "<8.0 || >= 11.0" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Helmich\\Psr7Assert\\": "src/" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "files": [ 31 | "vendor/helmich/phpunit-json-assert/src/Functions.php", 32 | "src/Functions.php" 33 | ] 34 | }, 35 | "config": { 36 | "sort-packages": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Constraint/BodyMatchesConstraint.php: -------------------------------------------------------------------------------- 1 | constraint = $constraint; 17 | } 18 | 19 | /** 20 | * Returns a string representation of the object. 21 | * 22 | * @return string 23 | */ 24 | public function toString(): string 25 | { 26 | return 'message body matches ' . $this->constraint->toString(); 27 | } 28 | 29 | protected function matches($other): bool 30 | { 31 | if (!$other instanceof MessageInterface) { 32 | return false; 33 | } 34 | 35 | $other->getBody()->rewind(); 36 | $body = $other->getBody()->getContents(); 37 | return $this->constraint->evaluate($body, '', true); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Constraint/HasHeaderConstraint.php: -------------------------------------------------------------------------------- 1 | name = strtolower($name); 27 | $this->constraint = $constraint; 28 | } 29 | 30 | /** 31 | * Returns a string representation of the object. 32 | * 33 | * @return string 34 | */ 35 | public function toString(): string 36 | { 37 | return "has header '{$this->name}' that {$this->constraint->toString()}"; 38 | } 39 | 40 | protected function matches($other): bool 41 | { 42 | if (!$other instanceof MessageInterface) { 43 | return false; 44 | } 45 | 46 | if (!$other->hasHeader($this->name)) { 47 | return false; 48 | } 49 | 50 | foreach ($other->getHeader($this->name) as $value) { 51 | if ($this->constraint->evaluate($value, '', true)) { 52 | return true; 53 | } 54 | } 55 | 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Constraint/HasMethodConstraint.php: -------------------------------------------------------------------------------- 1 | method = $method; 17 | } 18 | 19 | /** 20 | * Returns a string representation of the object. 21 | * 22 | * @return string 23 | */ 24 | public function toString(): string 25 | { 26 | return "has request method {$this->method}"; 27 | } 28 | 29 | protected function matches($other): bool 30 | { 31 | if (!$other instanceof RequestInterface) { 32 | return false; 33 | } 34 | 35 | return $other->getMethod() === $this->method; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Constraint/HasQueryParameterConstraint.php: -------------------------------------------------------------------------------- 1 | inner = new UrlEncodedMatches($nameMatcher, $valueMatcher); 17 | } 18 | 19 | protected function matches($other): bool 20 | { 21 | if (is_string($other)) { 22 | return $this->matchesString($other); 23 | } 24 | 25 | if ($other instanceof UriInterface) { 26 | return $this->matchesPsr7Uri($other); 27 | } 28 | 29 | if ($other instanceof RequestInterface) { 30 | return $this->matchesPsr7Uri($other->getUri()); 31 | } 32 | 33 | return false; 34 | } 35 | 36 | private function matchesPsr7Uri(UriInterface $other): bool 37 | { 38 | $queryString = $other->getQuery(); 39 | return $this->matchesQueryString($queryString); 40 | } 41 | 42 | private function matchesString(string $other): bool 43 | { 44 | $parsedUrl = parse_url($other); 45 | if (!isset($parsedUrl["query"])) { 46 | return false; 47 | } 48 | 49 | return $this->matchesQueryString($parsedUrl["query"]); 50 | } 51 | 52 | private function matchesQueryString(string $query): bool 53 | { 54 | return $this->inner->evaluate($query, "", true); 55 | } 56 | 57 | 58 | public function toString(): string 59 | { 60 | return 'query string ' . $this->inner->toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Constraint/HasQueryParametersConstraint.php: -------------------------------------------------------------------------------- 1 | $value) { 14 | $this->constraints[] = new HasQueryParameterConstraint($key, $value); 15 | } 16 | } 17 | 18 | public function matches($other): bool 19 | { 20 | foreach ($this->constraints as $constraint) { 21 | if (!$constraint->evaluate($other, "", true)) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | 29 | public function toString(): string 30 | { 31 | return join(" and ", array_map(function(HasQueryParameterConstraint $c) { 32 | return $c->toString(); 33 | }, $this->constraints)); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Constraint/HasStatusConstraint.php: -------------------------------------------------------------------------------- 1 | status = $status; 22 | } 23 | 24 | /** 25 | * Returns a string representation of the object. 26 | * 27 | * @return string 28 | */ 29 | public function toString(): string 30 | { 31 | return "response status {$this->status->toString()}"; 32 | } 33 | 34 | protected function matches($other): bool 35 | { 36 | if (!$other instanceof ResponseInterface) { 37 | return false; 38 | } 39 | 40 | return $this->status->evaluate($other->getStatusCode(), '', true); 41 | } 42 | 43 | protected function additionalFailureDescription($other): string 44 | { 45 | if ($other instanceof ResponseInterface) { 46 | return 'Actual status is ' . $other->getStatusCode() . ' and the body contains: ' . $other->getBody(); 47 | } 48 | return ''; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Constraint/HasUriConstraint.php: -------------------------------------------------------------------------------- 1 | uri = $uri; 17 | } 18 | 19 | /** 20 | * Returns a string representation of the object. 21 | * 22 | * @return string 23 | */ 24 | public function toString(): string 25 | { 26 | return "has request URI '{$this->uri}'"; 27 | } 28 | 29 | protected function matches($other): bool 30 | { 31 | if (!$other instanceof RequestInterface) { 32 | return false; 33 | } 34 | 35 | return $this->uri === (string) $other->getUri(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Constraint/IsAbsoluteUriConstraint.php: -------------------------------------------------------------------------------- 1 | nameMatcher = $nameMatcher; 26 | $this->valueMatcher = $valueMatcher; 27 | } 28 | 29 | protected function matches($other): bool 30 | { 31 | parse_str($other, $parsedQuery); 32 | 33 | foreach ($parsedQuery as $key => $value) { 34 | $nameMatches = $this->nameMatcher->evaluate($key, "", true); 35 | $valueMatches = $this->valueMatcher->evaluate($value, "", true); 36 | 37 | if ($nameMatches && $valueMatches) { 38 | return true; 39 | } 40 | } 41 | 42 | return false; 43 | } 44 | 45 | public function toString(): string 46 | { 47 | return 'contains a name matching ' . $this->nameMatcher->toString() . ' and value matching ' . $this->valueMatcher->toString(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/Constraint/UrlEncodedMatchesMany.php: -------------------------------------------------------------------------------- 1 | $value) { 14 | $this->constraints[] = new UrlEncodedMatches($key, $value); 15 | } 16 | } 17 | 18 | protected function matches($other): bool 19 | { 20 | foreach ($this->constraints as $constraint) { 21 | if (!$constraint->evaluate($other, "", true)) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | 29 | 30 | public function toString(): string 31 | { 32 | return join(" and ", array_map(function(HasQueryParameterConstraint $c) { 33 | return $c->toString(); 34 | }, $this->constraints)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Functions.php: -------------------------------------------------------------------------------- 1 | $constraint) { 193 | $headerConstraints[] = new HasHeaderConstraint($name, $constraint); 194 | } 195 | 196 | return Assert::logicalAnd(...$headerConstraints); 197 | } 198 | 199 | public static function hasHeaderEqualTo(string $name, string $expected): Constraint 200 | { 201 | return new HasHeaderConstraint($name, new IsEqual($expected)); 202 | } 203 | 204 | public static function bodyMatches(Constraint $constraint): Constraint 205 | { 206 | return new BodyMatchesConstraint($constraint); 207 | } 208 | 209 | /** 210 | * @param string|Constraint $name 211 | * @param string|Constraint|null $value 212 | * @return Constraint 213 | */ 214 | public static function hasQueryParameter($name, $value = null): Constraint 215 | { 216 | return new HasQueryParameterConstraint($name, $value); 217 | } 218 | 219 | public static function hasQueryParameters(array $parameters): Constraint 220 | { 221 | return new HasQueryParametersConstraint($parameters); 222 | } 223 | 224 | public static function bodyMatchesJson(array $constraints): Constraint 225 | { 226 | return Assert::logicalAnd( 227 | self::hasHeader('content-type', Assert::matchesRegularExpression(',^application/json(;.+)?$,')), 228 | self::bodyMatches( 229 | Assert::logicalAnd( 230 | Assert::isJson(), 231 | new JsonValueMatchesMany($constraints) 232 | ) 233 | ) 234 | ); 235 | } 236 | 237 | public static function bodyMatchesForm(array $constraints): Constraint 238 | { 239 | return Assert::logicalAnd( 240 | self::hasHeader('content-type', Assert::matchesRegularExpression(',^application/x-www-form-urlencoded(;.+)?$,')), 241 | self::bodyMatches(new UrlEncodedMatchesMany($constraints)) 242 | ); 243 | } 244 | 245 | /** 246 | * @return Constraint 247 | */ 248 | public static function isAbsoluteUri(): Constraint 249 | { 250 | return new IsAbsoluteUriConstraint(); 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/Psr7AssertionsClass.php: -------------------------------------------------------------------------------- 1 |