Skip to content

Commit 680e539

Browse files
authored
Merge pull request #59 from tyx/feature/context-on-exception
Add context text to expectation exception
2 parents d40614f + eb52677 commit 680e539

File tree

9 files changed

+297
-76
lines changed

9 files changed

+297
-76
lines changed

src/ExpectationFailed.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Rezzza\RestApiBehatExtension;
4+
5+
abstract class ExpectationFailed extends \Exception
6+
{
7+
abstract function getContextText();
8+
9+
/**
10+
* Returns exception message with additional context info.
11+
*
12+
* @return string
13+
*/
14+
public function __toString()
15+
{
16+
try {
17+
$contextText = $this->pipeString($this->trimString($this->getContextText())."\n");
18+
$string = sprintf("%s\n\n%s", $this->getMessage(), $contextText);
19+
} catch (\Exception $e) {
20+
return $this->getMessage();
21+
}
22+
23+
return $string;
24+
}
25+
26+
/**
27+
* Prepends every line in a string with pipe (|).
28+
*
29+
* @param string $string
30+
*
31+
* @return string
32+
*/
33+
protected function pipeString($string)
34+
{
35+
return '| '.strtr($string, array("\n" => "\n| "));
36+
}
37+
38+
/**
39+
* Trims string to specified number of chars.
40+
*
41+
* @param string $string response content
42+
* @param int $count trim count
43+
*
44+
* @return string
45+
*/
46+
protected function trimString($string, $count = 1000)
47+
{
48+
$string = trim($string);
49+
if ($count < mb_strlen($string)) {
50+
return mb_substr($string, 0, $count - 3).'...';
51+
}
52+
53+
return $string;
54+
}
55+
}

src/Json/JsonContext.php

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ public function responseShouldBeInJson()
4343
*/
4444
public function theJsonNodeShouldBeEqualTo($jsonNode, $expectedValue)
4545
{
46-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
47-
48-
$this->asserter->variable($realValue)->isEqualTo($expectedValue);
46+
$this->assert(function () use ($jsonNode, $expectedValue) {
47+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
48+
$this->asserter->variable($realValue)->isEqualTo($expectedValue);
49+
});
4950
}
5051

5152
/**
@@ -54,39 +55,43 @@ public function theJsonNodeShouldBeEqualTo($jsonNode, $expectedValue)
5455
*/
5556
public function theJsonNodeShouldHaveElements($jsonNode, $expectedNth)
5657
{
57-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
58-
59-
$this->asserter->phpArray($realValue)->hasSize($expectedNth);
58+
$this->assert(function () use ($jsonNode, $expectedNth) {
59+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
60+
$this->asserter->phpArray($realValue)->hasSize($expectedNth);
61+
});
6062
}
6163

6264
/**
6365
* @Then /^the JSON array node "(?P<jsonNode>[^"]*)" should contain "(?P<expectedValue>.*)" element$/
6466
*/
6567
public function theJsonArrayNodeShouldContainElements($jsonNode, $expectedValue)
6668
{
67-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
68-
69-
$this->asserter->phpArray($realValue)->contains($expectedValue);
69+
$this->assert(function () use ($jsonNode, $expectedValue) {
70+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
71+
$this->asserter->phpArray($realValue)->contains($expectedValue);
72+
});
7073
}
7174

7275
/**
7376
* @Then /^the JSON array node "(?P<jsonNode>[^"]*)" should not contain "(?P<expectedValue>.*)" element$/
7477
*/
7578
public function theJsonArrayNodeShouldNotContainElements($jsonNode, $expectedValue)
7679
{
77-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
78-
79-
$this->asserter->phpArray($realValue)->notContains($expectedValue);
80+
$this->assert(function () use ($jsonNode, $expectedValue) {
81+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
82+
$this->asserter->phpArray($realValue)->notContains($expectedValue);
83+
});
8084
}
8185

8286
/**
8387
* @Then /^the JSON node "(?P<jsonNode>[^"]*)" should contain "(?P<expectedValue>.*)"$/
8488
*/
8589
public function theJsonNodeShouldContain($jsonNode, $expectedValue)
8690
{
87-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
88-
89-
$this->asserter->string((string) $realValue)->contains($expectedValue);
91+
$this->assert(function () use ($jsonNode, $expectedValue) {
92+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
93+
$this->asserter->string((string) $realValue)->contains($expectedValue);
94+
});
9095
}
9196

9297
/**
@@ -96,9 +101,10 @@ public function theJsonNodeShouldContain($jsonNode, $expectedValue)
96101
*/
97102
public function theJsonNodeShouldNotContain($jsonNode, $unexpectedValue)
98103
{
99-
$realValue = $this->evaluateJsonNodeValue($jsonNode);
100-
101-
$this->asserter->string((string) $realValue)->notContains($unexpectedValue);
104+
$this->assert(function () use ($jsonNode, $unexpectedValue) {
105+
$realValue = $this->evaluateJsonNodeValue($jsonNode);
106+
$this->asserter->string((string) $realValue)->notContains($unexpectedValue);
107+
});
102108
}
103109

104110
/**
@@ -111,7 +117,7 @@ public function theJsonNodeShouldExist($jsonNode)
111117
try {
112118
$this->evaluateJsonNodeValue($jsonNode);
113119
} catch (\Exception $e) {
114-
throw new \Exception(sprintf("The node '%s' does not exist.", $jsonNode), 0, $e);
120+
throw new WrongJsonExpectation(sprintf("The node '%s' does not exist.", $jsonNode), $this->readJson(), $e);
115121
}
116122
}
117123

@@ -131,7 +137,11 @@ public function theJsonNodeShouldNotExist($jsonNode)
131137
}
132138

133139
if ($e === null) {
134-
throw new \Exception(sprintf("The node '%s' exists and contains '%s'.", $jsonNode, json_encode($realValue)));
140+
throw new WrongJsonExpectation(
141+
sprintf("The node '%s' exists and contains '%s'.", $jsonNode, json_encode($realValue)),
142+
$this->readJson(),
143+
$e
144+
);
135145
}
136146
}
137147

@@ -142,9 +152,11 @@ public function theJsonShouldBeValidAccordingToThisSchema(PyStringNode $jsonSche
142152
{
143153
$tempFilename = tempnam(sys_get_temp_dir(), 'rae');
144154
file_put_contents($tempFilename, $jsonSchemaContent);
145-
$this->jsonInspector->validateJson(
146-
new JsonSchema($tempFilename)
147-
);
155+
$this->assert(function () use ($tempFilename) {
156+
$this->jsonInspector->validateJson(
157+
new JsonSchema($tempFilename)
158+
);
159+
});
148160
unlink($tempFilename);
149161
}
150162

@@ -155,11 +167,11 @@ public function theJsonShouldBeValidAccordingToTheSchema($filename)
155167
{
156168
$filename = $this->resolveFilename($filename);
157169

158-
$this->jsonInspector->validateJson(
159-
new JsonSchema(
160-
$filename
161-
)
162-
);
170+
$this->assert(function () use ($filename) {
171+
$this->jsonInspector->validateJson(
172+
new JsonSchema($filename)
173+
);
174+
});
163175
}
164176

165177
/**
@@ -175,7 +187,9 @@ public function theJsonShouldBeEqualTo(PyStringNode $jsonContent)
175187
throw new \Exception('The expected JSON is not a valid');
176188
}
177189

178-
$this->asserter->castToString($realJsonValue)->isEqualTo((string) $expectedJsonValue);
190+
$this->assert(function () use ($realJsonValue, $expectedJsonValue) {
191+
$this->asserter->castToString($realJsonValue)->isEqualTo((string) $expectedJsonValue);
192+
});
179193
}
180194

181195
private function evaluateJsonNodeValue($jsonNode)
@@ -212,4 +226,13 @@ private function resolveFilename($filename)
212226

213227
return realpath($filename);
214228
}
229+
230+
private function assert(callable $assertion)
231+
{
232+
try {
233+
$assertion();
234+
} catch (\Exception $e) {
235+
throw new WrongJsonExpectation($e->getMessage(), $this->readJson(), $e);
236+
}
237+
}
215238
}

src/Json/WrongJsonExpectation.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Rezzza\RestApiBehatExtension\Json;
4+
5+
use Rezzza\RestApiBehatExtension\ExpectationFailed;
6+
7+
class WrongJsonExpectation extends ExpectationFailed
8+
{
9+
private $json;
10+
11+
public function __construct($message, Json $json, $previous = null)
12+
{
13+
$this->json = $json;
14+
parent::__construct($message, 0, $previous);
15+
}
16+
17+
public function getContextText()
18+
{
19+
return $this->json->encode(true);
20+
}
21+
}

src/Rest/HttpExchangeFormatter.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Rezzza\RestApiBehatExtension\Rest;
4+
5+
use Psr\Http\Message\ResponseInterface;
6+
use Psr\Http\Message\RequestInterface;
7+
8+
class HttpExchangeFormatter
9+
{
10+
private $request;
11+
12+
private $response;
13+
14+
public function __construct(RequestInterface $request, ResponseInterface $response)
15+
{
16+
$this->request = $request;
17+
$this->response = $response;
18+
}
19+
20+
public function formatRequest()
21+
{
22+
return sprintf(
23+
"%s %s :\n%s%s\n",
24+
$this->request->getMethod(),
25+
$this->request->getUri(),
26+
$this->getRawHeaders($this->request->getHeaders()),
27+
$this->request->getBody()
28+
);
29+
}
30+
31+
public function formatFullExchange()
32+
{
33+
return sprintf(
34+
"%s %s :\n%s %s\n%s%s\n",
35+
$this->request->getMethod(),
36+
$this->request->getUri()->__toString(),
37+
$this->response->getStatusCode(),
38+
$this->response->getReasonPhrase(),
39+
$this->getRawHeaders($this->response->getHeaders()),
40+
$this->response->getBody()
41+
);
42+
}
43+
44+
/**
45+
* @param array $headers
46+
* @return string
47+
*/
48+
private function getRawHeaders(array $headers)
49+
{
50+
$rawHeaders = '';
51+
foreach ($headers as $key => $value) {
52+
$rawHeaders .= sprintf("%s: %s\n", $key, is_array($value) ? implode(", ", $value) : $value);
53+
}
54+
$rawHeaders .= "\n";
55+
56+
return $rawHeaders;
57+
}
58+
}

src/Rest/ResponseStorage.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<?php
22

3-
namespace Rest;
4-
53
namespace Rezzza\RestApiBehatExtension\Rest;
64

75
interface ResponseStorage
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Rezzza\RestApiBehatExtension\Rest;
4+
5+
use Rezzza\RestApiBehatExtension\ExpectationFailed;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\RequestInterface;
8+
9+
class WrongResponseExpectation extends ExpectationFailed
10+
{
11+
private $request;
12+
13+
private $response;
14+
15+
public function __construct($message, RequestInterface $request, ResponseInterface $response, $previous = null)
16+
{
17+
$this->request = $request;
18+
$this->response = $response;
19+
parent::__construct($message, 0, $previous);
20+
}
21+
22+
public function getContextText()
23+
{
24+
$formatter = new HttpExchangeFormatter($this->request, $this->response);
25+
26+
return $formatter->formatFullExchange();
27+
}
28+
}

0 commit comments

Comments
 (0)