예제 #1
0
 /**
  * Taken from Mink\BrowserKitDriver
  *
  * @param Response $response
  *
  * @return \Symfony\Component\BrowserKit\Response
  */
 protected function createResponse(Response $response)
 {
     $contentType = $response->getHeader('Content-Type');
     $matches = null;
     if (!$contentType or strpos($contentType, 'charset=') === false) {
         $body = $response->getBody(true);
         if (preg_match('/\\<meta[^\\>]+charset *= *["\']?([a-zA-Z\\-0-9]+)/i', $body, $matches)) {
             $contentType .= ';charset=' . $matches[1];
         }
         $response->setHeader('Content-Type', $contentType);
     }
     $headers = $response->getHeaders();
     $status = $response->getStatusCode();
     $matchesMeta = null;
     $matchesHeader = null;
     $isMetaMatch = preg_match('/\\<meta[^\\>]+http-equiv="refresh" content="(\\d*)\\s*;?\\s*url=(.*?)"/i', $response->getBody(true), $matchesMeta);
     $isHeaderMatch = preg_match('~(\\d*);?url=(.*)~', (string) $response->getHeader('Refresh'), $matchesHeader);
     $matches = $isMetaMatch ? $matchesMeta : $matchesHeader;
     if (!empty($matches) && (empty($matches[1]) || $matches[1] < $this->refreshMaxInterval)) {
         $uri = $this->getAbsoluteUri($matches[2]);
         $partsUri = parse_url($uri);
         $partsCur = parse_url($this->getHistory()->current()->getUri());
         foreach ($partsCur as $key => $part) {
             if ($key === 'fragment') {
                 continue;
             }
             if (!isset($partsUri[$key]) || $partsUri[$key] !== $part) {
                 $status = 302;
                 $headers['Location'] = $uri;
                 break;
             }
         }
     }
     return new BrowserKitResponse($response->getBody(), $status, $headers);
 }
예제 #2
0
 /**
  * Response constructor
  *
  * @param  HttpResponse $httpResponse
  * @return self
  */
 public function __construct(HttpResponse $httpResponse)
 {
     if (stripos($httpResponse->getHeader('Content-Type'), 'text/javascript') !== false) {
         $this->_response = $this->processJson($httpResponse->getBody());
     } else {
         $this->_response = $this->processXml($httpResponse->getBody());
     }
 }
예제 #3
0
 /**
  * @return ErrorResponse|SuccessResponse
  */
 public function deduce()
 {
     /* @var array $response */
     $response = (array) $this->response->json();
     if (array_key_exists('type', $response) && $response['type'] === 'error') {
         return new ErrorResponse($this->response->getStatusCode(), $this->response->getHeaders(), $this->response->getBody());
     }
     return new SuccessResponse($this->response->getStatusCode(), $this->response->getHeaders(), $this->response->getBody());
 }
 private function getResponse(HttpResponse $httpResponse)
 {
     $response = new Response();
     if ($httpResponse->getBody()) {
         $resp = (string) $httpResponse->getBody();
         $decoded = json_decode($resp, true);
         $response->setBody($decoded);
     }
     return $response;
 }
예제 #5
0
 protected function handleResponse(Response $response)
 {
     $code = $response->getStatusCode();
     if ($code == 200) {
         return json_decode($response->getBody()->getContents(), true);
     }
     if ($code == 401 && $this->requiresToken) {
         // Unauthorized, invalidate token
         $this->tokenStore->storeToken(null);
     }
     throw new ApiException('Request failed, received the following status: ' . $response->getStatusCode() . ' Body: ' . $response->getBody()->getContents());
 }
예제 #6
0
 /**
  * @param GuzzleResponse $guzzleResponse
  *
  * @return Response
  */
 protected function createResponseFromGuzzleResponse(GuzzleResponse $guzzleResponse)
 {
     $content = null;
     if ($guzzleResponse->getBody() !== null) {
         $content = $guzzleResponse->getBody()->getContents();
     }
     $response = new Response($content, $guzzleResponse->getStatusCode());
     $response->setHeaders($guzzleResponse->getHeaders());
     $deniedHeaders = array('transfer-encoding', 'x-powered-by', 'content-length', 'content-encoding');
     foreach ($deniedHeaders as $headerName) {
         $response->removeHeader($headerName);
     }
     return $response;
 }
예제 #7
0
파일: Response.php 프로젝트: efiku/Scraper
 /**
  * Parse body of response
  *
  * @return Crawler | array | string
  */
 private function parseBody()
 {
     $type = $this->getType();
     $body = (string) $this->resource->getBody();
     if (!$body) {
         return '';
     }
     if (in_array($type, ['text/html', 'text/xml'])) {
         return new Crawler($body);
     }
     if ($type === 'application/json') {
         return $this->resource->json();
     }
     return $body;
 }
예제 #8
0
파일: Client.php 프로젝트: reliv/git
 protected function getMessages(Response $response)
 {
     $body = (string) $response->getBody();
     if (empty($body)) {
         throw new InvalidResponseException('There was no messages returned from the server at: ' . $this->uri);
     }
     $messages = array();
     $messageCounter = 0;
     while ($body) {
         $lineLengthHex = substr($body, 0, 4);
         if (strlen($lineLengthHex) != 4) {
             throw new InvalidResponseException('A corrupt package was received from the server.  Uri: ' . $this->uri);
         }
         if ($lineLengthHex == '0000') {
             $messageCounter++;
             $body = substr_replace($body, '', 0, 4);
             continue;
         }
         $lineLength = hexdec($lineLengthHex);
         $line = substr($body, 4, $lineLength - 4);
         $body = substr_replace($body, '', 0, $lineLength);
         $messages[$messageCounter][] = trim($line);
     }
     return $messages;
 }
예제 #9
0
 /**
  * @param Response $response
  * @return array
  */
 public static function parseQuery(Response $response)
 {
     $responseBody = $response->getBody();
     $params = [];
     parse_str($responseBody, $params);
     return $params;
 }
예제 #10
0
 /**
  * @return string
  */
 protected function extractContentTypeStringOutOfMetaTag()
 {
     $matches = array();
     $body = (string) $this->response->getBody();
     @preg_match('~<meta[^>]*charset=(?<charset>[^"]*)[^>]*>~is', $body, $matches);
     return is_array($matches) && array_key_exists('charset', $matches) && $matches['charset'] != '' ? $matches['charset'] : '';
 }
예제 #11
0
파일: Http.php 프로젝트: zimbra-api/soap
 /**
  * Returns last SOAP response.
  *
  * @return mix The last SOAP response, as an XML string.
  */
 public function lastResponse()
 {
     if ($this->response instanceof Response) {
         return $this->response->getBody();
     }
     return null;
 }
예제 #12
0
 protected function handleResponse(Response $response)
 {
     if ($response->getStatusCode() == 200) {
         return $response->getBody()->getContents();
     }
     throw new ApiException('Request failed, received the following status: ' . $response->getStatusCode() . ' Body: ' . $response->getBody()->getContents());
 }
예제 #13
0
 function debug(\GuzzleHttp\Message\Response $response)
 {
     $this->dump_respuesta = 'status: ' . $response->getStatusCode() . "<br/>body: <br/>" . $response->getBody();
     //un string encodeado utf-8
     $this->dump_url = $response->getEffectiveUrl();
     //un string encodeado utf-8
 }
 public function getBody()
 {
     $content = parent::getBody()->getContents();
     if ($content) {
         $this->content = $content;
     }
     return $this->content;
 }
 protected function saveResponseToFile(Response &$response)
 {
     $fileName = __DIR__ . '\\json\\' . sizeof($this->fileHandles) . '.json';
     $reponseSavedToFile = file_put_contents($fileName, $response->getBody());
     if ($reponseSavedToFile != false) {
         $this->fileHandles[] = $fileName;
     }
     unset($response);
 }
예제 #16
0
파일: Json.php 프로젝트: talkrz/rest-spec
 public function validateBody(Response $response, Spec\Response $responseSpec)
 {
     $actualBody = (string) $response->getBody();
     $actualBodyData = json_decode($actualBody, true);
     if ($actualBodyData !== $responseSpec->getBody()) {
         $message = sprintf("\t\t<error>JSON in body of the response is invalid, actual:</error>\n%s\n\t\t<error>Expected:</error>\n%s", $this->getOutput()->formatArray($actualBodyData, 3), $this->getOutput()->formatArray($responseSpec->getBody(), 3));
         $this->addViolation($message);
     }
 }
예제 #17
0
 public static function parse(\GuzzleHttp\Message\Response $response)
 {
     $body = (string) $response->getBody();
     $params = json_decode($body, true);
     if ($params !== NULL) {
         return $params;
     }
     parse_str($body, $params);
     return $params;
 }
예제 #18
0
 public function parse(Response $response)
 {
     $collection = new Collection();
     if (!$response->getBody()) {
         return $collection;
     }
     // help bad responses be more multipart compliant
     $body = "\r\n" . $response->getBody()->__toString() . "\r\n";
     // multipart
     preg_match('/boundary\\=\\"(.*?)\\"/', $response->getHeader('Content-Type'), $matches);
     if (isset($matches[1])) {
         $boundary = $matches[1];
     } else {
         preg_match('/boundary\\=(.*?)(\\s|$|\\;)/', $response->getHeader('Content-Type'), $matches);
         $boundary = $matches[1];
     }
     // strip quotes off of the boundary
     $boundary = preg_replace('/^\\"(.*?)\\"$/', '\\1', $boundary);
     // clean up the body to remove a reamble and epilogue
     $body = preg_replace('/^(.*?)\\r\\n--' . $boundary . '\\r\\n/', "\r\n--{$boundary}\r\n", $body);
     // make the last one look like the rest for easier parsing
     $body = preg_replace('/\\r\\n--' . $boundary . '--/', "\r\n--{$boundary}\r\n", $body);
     // cut up the message
     $multi_parts = explode("\r\n--{$boundary}\r\n", $body);
     // take off anything that happens before the first boundary (the preamble)
     array_shift($multi_parts);
     // take off anything after the last boundary (the epilogue)
     array_pop($multi_parts);
     $message_parser = new MessageParser();
     $parser = new Single();
     // go through each part of the multipart message
     foreach ($multi_parts as $part) {
         // get Guzzle to parse this multipart section as if it's a whole HTTP message
         $parts = $message_parser->parseResponse("HTTP/1.1 200 OK\r\n" . $part);
         // now throw this single faked message through the Single GetObject response parser
         $single = new Response($parts['code'], $parts['headers'], Stream::factory($parts['body']));
         $obj = $parser->parse($single);
         // add information about this multipart to the returned collection
         $collection->push($obj);
     }
     return $collection;
 }
 /**
  * @param Response $response
  *
  * @return string
  */
 protected static function createMessage(Response $response)
 {
     if ($response->getStatusCode() != 400) {
         return '[' . $response->getStatusCode() . '] A HTTP error has occurred: ' . $response->getBody(true);
     }
     $message = 'Some errors occurred:';
     foreach ($response->xml()->error as $error) {
         $message .= PHP_EOL . '[' . (string) $error->code . '] ' . (string) $error->message;
     }
     return $message;
 }
예제 #20
0
 public function testDoesTheSameAsResponseWhenDereferenced()
 {
     $str = Stream::factory('foo');
     $response = new Response(200, ['Foo' => 'bar'], $str);
     $future = MockTest::createFuture(function () use($response) {
         return $response;
     });
     $this->assertFalse($this->readAttribute($future, 'isRealized'));
     $this->assertEquals(200, $future->getStatusCode());
     $this->assertTrue($this->readAttribute($future, 'isRealized'));
     // Deref again does nothing.
     $future->wait();
     $this->assertTrue($this->readAttribute($future, 'isRealized'));
     $this->assertEquals('bar', $future->getHeader('Foo'));
     $this->assertEquals(['bar'], $future->getHeaderAsarray('Foo'));
     $this->assertSame($response->getHeaders(), $future->getHeaders());
     $this->assertSame($response->getBody(), $future->getBody());
     $this->assertSame($response->getProtocolVersion(), $future->getProtocolVersion());
     $this->assertSame($response->getEffectiveUrl(), $future->getEffectiveUrl());
     $future->setEffectiveUrl('foo');
     $this->assertEquals('foo', $response->getEffectiveUrl());
     $this->assertSame($response->getReasonPhrase(), $future->getReasonPhrase());
     $this->assertTrue($future->hasHeader('foo'));
     $future->removeHeader('Foo');
     $this->assertFalse($future->hasHeader('foo'));
     $this->assertFalse($response->hasHeader('foo'));
     $future->setBody(Stream::factory('true'));
     $this->assertEquals('true', (string) $response->getBody());
     $this->assertTrue($future->json());
     $this->assertSame((string) $response, (string) $future);
     $future->setBody(Stream::factory('<a><b>c</b></a>'));
     $this->assertEquals('c', (string) $future->xml()->b);
     $future->addHeader('a', 'b');
     $this->assertEquals('b', $future->getHeader('a'));
     $future->addHeaders(['a' => '2']);
     $this->assertEquals('b, 2', $future->getHeader('a'));
     $future->setHeader('a', '2');
     $this->assertEquals('2', $future->getHeader('a'));
     $future->setHeaders(['a' => '3']);
     $this->assertEquals(['a' => ['3']], $future->getHeaders());
 }
예제 #21
0
 /**
  * @param Response $response
  * @return \GuzzleHttp\Stream\StreamInterface|mixed|null|string
  * @throws ApiException
  */
 protected function handleResponse(Response $response)
 {
     if ($response->getStatusCode() == 200) {
         $stream = $response->getBody();
         if ($this->returnStream == true) {
             return $stream;
         } else {
             return parent::handleResponse($response);
         }
     }
     throw new ApiException('Request failed, received the following status: ' . $response->getStatusCode() . ' Body: ' . $response->getBody()->getContents());
 }
예제 #22
0
파일: Guzzle.php 프로젝트: aleguisf/fvdev1
 /**
  * Taken from Mink\BrowserKitDriver
  *
  * @param Response $response
  *
  * @return \Symfony\Component\BrowserKit\Response
  */
 protected function createResponse(Response $response)
 {
     $contentType = $response->getHeader('Content-Type');
     if (!$contentType or strpos($contentType, 'charset=') === false) {
         $body = $response->getBody(true);
         if (preg_match('/\\<meta[^\\>]+charset *= *["\']?([a-zA-Z\\-0-9]+)/i', $body, $matches)) {
             $contentType .= ';charset=' . $matches[1];
         }
         $response->setHeader('Content-Type', $contentType);
     }
     $headers = $response->getHeaders();
     $status = $response->getStatusCode();
     if (preg_match('/\\<meta[^\\>]+http-equiv="refresh" content=".*?url=(.*?)"/i', $response->getBody(true), $matches)) {
         $status = 302;
         $headers['Location'] = $matches[1];
     }
     if (preg_match('~url=(.*)~', (string) $response->getHeader('Refresh'), $matches)) {
         $status = 302;
         $headers['Location'] = $matches[1];
     }
     return new BrowserKitResponse($response->getBody(), $status, $headers);
 }
예제 #23
0
 /**
  * @param \GuzzleHttp\Message\Response $response
  */
 function __construct($response)
 {
     parent::__construct($response->getStatusCode(), $response->getHeaders(), $response->getBody());
     $jsonBody = $this->json();
     if (array_key_exists("code", $jsonBody)) {
         $this->internal_code = $jsonBody["code"];
         $this->internal_message = $jsonBody["message"];
         $this->internal_type = $jsonBody["type"];
     }
     if (array_key_exists("atoken", $jsonBody) || array_key_exists("uid", $jsonBody)) {
         $this->internal_code = 200;
         $this->internal_type = $jsonBody["type"] = "oauthResponse";
     }
 }
예제 #24
0
 /**
  * Construct a Ping response from an HTTP response.
  *
  * @param Response $response
  */
 public function __construct(Response $response)
 {
     $this->response = $response;
     $this->status = $response->getStatusCode();
     $this->error = null;
     $this->xml = null;
     $this->body = $response->getBody();
     try {
         $this->xml = $response->xml();
     } catch (Exception $ex) {
         $this->error = $ex->getMessage();
     } catch (XmlParseException $ex) {
         $this->error = $ex->getMessage();
     }
 }
예제 #25
0
 /**
  * Making request using Guzzle
  *
  * @param string $method Type of request, either POST, GET, PUT or DELETE
  * @param string $endpoint The operation / task for API
  * @param array $data The parameter need to be passed
  * @param array $options The options like header, body, etc
  *
  * @return EntityBodyInterface|string
  * @throws \Exception
  */
 private function sendRequest($method, $endpoint, array $data = array(), array $options = array())
 {
     $uri = $this->buildUri($endpoint);
     if ($method === "GET" || $method === "PUT") {
         $uri = $this->buildUri($endpoint, $data);
     } elseif (count($data)) {
         $options['body'] = $data;
     }
     $this->request = $this->client->createRequest($method, $uri, $options);
     $this->response = $this->client->send($this->request);
     if ($this->response->getStatusCode() >= 400) {
         $bt = debug_backtrace();
         $caller = $bt[2];
         if (isset($caller['class']) && $caller['class'] === get_class(new StacklaModel())) {
             $json = (string) $this->response->getBody();
             if (JsonValidator::validate($json, true)) {
                 $content = json_decode($json, true);
                 if (isset($content['errors'])) {
                     $caller['object']->fromArray($content);
                 }
             }
         }
         if ($this->logger) {
             $this->logger->addError('-> REQUEST [' . $this->request->getMethod() . ' - ' . $this->request->getUrl() . "]", array($this->request->getMethod() !== "GET" ? (string) $this->request->getBody() : ""));
             $this->logger->addError('<- RESPONSE [' . $this->response->getStatusCode() . ':' . $this->response->getReasonPhrase() . "]", array((string) $this->response->getBody()));
         }
     } else {
         if ($this->logger) {
             $this->logger->addInfo('-> REQUEST [' . $this->request->getMethod() . ' - ' . $this->request->getUrl() . "]", array($this->request->getMethod() !== "GET" ? (string) $this->request->getBody() : ""));
             $this->logger->addInfo('<- RESPONSE [' . $this->response->getStatusCode() . ':' . $this->response->getReasonPhrase() . "]", array($this->response->json()));
         }
     }
     $statusCode = $this->response->getStatusCode();
     switch ($statusCode) {
         case 200:
             return (string) $this->response->getBody();
         case 400:
             throw ApiException::create(sprintf("Server return %s error code. Bad request: The request could not be understood. %s", $this->response->getStatusCode(), (string) $this->response->getBody()), $statusCode, (string) $this->response->getBody());
         case 401:
             throw ApiException::create(sprintf("Server return %s error code. Unauthorized: Authentication credentials invalid or not authorised to access resource", $this->response->getStatusCode()), $statusCode, (string) $this->response->getBody());
         case 403:
             throw ApiException::create(sprintf("\n                  Server return %s error code. Rate limit exceeded: Too many requests in the current time window", $this->response->getStatusCode()), $statusCode, (string) $this->response->getBody());
         case 404:
             throw ApiException::create(sprintf("Server return %s error code. Invalid resource: Invalid resource specified or resource not found", $this->response->getStatusCode()), $statusCode, (string) $this->response->getBody());
         default:
             throw ApiException::create(sprintf("Server return %s error code.Server error: An error on the server prohibited a successful response; please contact support. %s", $this->response->getStatusCode(), (string) $this->response->getBody()), $statusCode, (string) $this->response->getBody());
     }
 }
 /**
  * @param Response $httpResponse
  * @return array
  * @throws \RuntimeException
  */
 protected function extractDataFromResponse($httpResponse, GiropayResponse $giropayResponse)
 {
     $response = new PaymentResponseDTO(PaymentType::$BANK_ACCOUNT, GiropayPaymentGatewayType::$GIROPAY);
     $response->rawResponse($httpResponse->getBody(true));
     try {
         $data = $httpResponse->json();
         if (!array_key_exists("rc", $data) || !is_numeric($data["rc"])) {
             throw new \RuntimeException("Missing required response parameter rc");
         }
         if (!array_key_exists($data["rc"], GiropayResultType::$TYPES)) {
             throw new \RuntimeException("Unknown Result Code: " . $data["rc"]);
         }
         $result = GiropayResultType::$TYPES[$data["rc"]];
         $giropayResponse->setResult($result);
         if (GiropayResultType::$OK->equals($result) && !$this->verifyHttpResponseHash($httpResponse)) {
             throw new \RuntimeException("The validation hash was invalid");
         }
     } catch (Guzzle\Common\Exception\RuntimeException $e) {
         throw new \RuntimeException("Json payload could not be parsed", 0, $e);
     }
     return $data;
 }
예제 #27
0
 /**
  * Announces HTTP request to Wildfire channel
  *
  * @param GuzzleHttp\Message\Request
  * @param GuzzleHttp\Message\Response   when dealing with error events, response may not be populated
  * @param float $elapsed
  */
 public function publishRequest(Request $request, Response $response = null, $elapsed = 0)
 {
     $request_body = $request->getBody();
     $request_preview = '';
     if ($request_body) {
         $request_body->seek(0);
         // rewind the cursor in case a read was already done
         $request_preview = $request_body->read($this->_preview_length);
         $request_body->seek(0);
         // rewind the cursor, so subsequent reads are not affected
     }
     // Ensure response is populated before extracting body from it
     $response_body = $response ? $response->getBody() : '';
     $response_preview = '';
     if ($response_body) {
         $response_body->seek(0);
         // rewind the cursor, in case a read was already done
         $response_preview = $response_body->read($this->_preview_length);
         $response_body->seek(0);
         // rewind the cursor, so subsequent reads are not affected
     }
     $phrase = $response ? $response->getReasonPhrase() : self::ERROR_NO_RESPONSE;
     $table = [];
     $table[] = ['Key', 'Value'];
     $table[] = ['Phrase', $phrase];
     $table[] = ['Host', $request->getHost()];
     $table[] = ['Protocol', $request->getScheme()];
     $table[] = ['User Agent', $request->getHeader('User-Agent')];
     $table[] = ['Request', $request_preview];
     $table[] = ['Response', $response_preview];
     if ($response && $response->getEffectiveUrl() != $request->getUrl()) {
         $table[] = ['Effective URL', $response->getEffectiveUrl()];
     }
     $elapsed = number_format($elapsed, 4);
     $status = $response ? $response->getStatusCode() : 0;
     $message = sprintf("%s <%s> (%d) %s (%f)s", $this->_remote_prefix, $request->getMethod(), $status, $request->getUrl(), $elapsed);
     $this->_client->table($message, $table);
 }
 /**
  * @param $response HttpResponse
  *
  * @throws ServerException
  */
 private function getGuzzleResponseData($response)
 {
     if (!is_a($response, 'GuzzleHttp\\Message\\Response')) {
         $this->splitResponseToHeadersArrayAndBody($response);
         $response = new Response($this->status, $this->headers, null, []);
         $this->body = (string) $this->body;
         //            $this->status = (int) explode(' ', $this->status)[1];
         $statusLineArray = explode(" ", trim($this->headers['status'][0]));
         $this->status = (int) $statusLineArray[1];
     } else {
         $this->status = $response->getStatusCode();
         $this->body = (string) $response->getBody();
         $response->requestHandler = $this->request->requestHandler;
     }
     $this->headers = $response->getHeaders();
     if ($this->verboseExtractStatusLine === true) {
         $this->getVerboseStatusLine($response);
     }
     if (in_array(intval($this->status), $this->enabledHttpServerExceptions)) {
         $this->getVerboseStatusLine($response);
         throw new ServerException($this->statusPhrase, $this->status);
     }
 }
예제 #29
0
 /**
  * Return the raw XML response from the web service.
  * @return string
  */
 public function responseContent()
 {
     return $this->http_response_object->getBody();
 }
예제 #30
-1
 public function evaluateResponse(Response $response)
 {
     $errors = [];
     try {
         // Test response code
         if (array_key_exists('response.statusCode', $this->expectations)) {
             $this->expectations['response.statusCode']->evaluate((int) $response->getStatusCode(), 'Status code was expected to be `%s` but was actually `' . $response->getStatusCode() . '`');
         }
     } catch (AssertionFailedException $e) {
         $errors[] = $e->getMessage();
     }
     // Test headers
     foreach ($this->expectations as $name => $expectation) {
         try {
             if (substr($name, 0, 8) === 'headers.') {
                 $headerName = substr($name, 8);
                 $headerValue = $response->getHeader($headerName);
                 $this->expectations['headers.' . strtolower($headerName)]->evaluate($headerValue, 'Header `' . $headerName . '` expected to be `%s` but was `%s`');
             }
         } catch (AssertionFailedException $e) {
             $errors[] = $e->getMessage();
         }
     }
     // Test body
     $body = json_decode($response->getBody(), true);
     foreach ($this->expectations as $name => $expectation) {
         try {
             if (substr($name, 0, 5) === 'body.') {
                 $keyName = substr($name, 5);
                 $keyValue = array_get($body, $keyName);
                 $this->expectations['body.' . strtolower($keyName)]->evaluate($keyValue, 'Body key `' . $keyName . '` expected to be `%s` but was `%s`');
             }
         } catch (AssertionFailedException $e) {
             $errors[] = $e->getMessage();
         }
     }
     return $errors;
 }