Skip to content

Commit a888ecb

Browse files
committed
Merge branch 'conditional-responses'
2 parents d41093e + 6f5ec0d commit a888ecb

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
## 1.2.1 - 2019-02-21
4+
5+
### Added
6+
7+
- Conditional mock functionality
8+
39
## 1.2.0 - 2019-01-19
410

511
### Added

spec/ClientSpec.php

+48
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Http\Client\HttpAsyncClient;
66
use Http\Client\HttpClient;
7+
use Http\Message\RequestMatcher;
78
use Http\Message\ResponseFactory;
89
use Http\Mock\Client;
910
use Psr\Http\Message\RequestInterface;
@@ -106,4 +107,51 @@ function it_reset(
106107

107108
$this->getRequests()->shouldReturn([]);
108109
}
110+
function it_returns_response_if_request_matcher_matches(
111+
RequestMatcher $matcher,
112+
RequestInterface $request,
113+
ResponseInterface $response
114+
) {
115+
$matcher->matches($request)->willReturn(true);
116+
$this->on($matcher, $response);
117+
$this->sendRequest($request)->shouldReturn($response);
118+
}
119+
120+
function it_throws_exception_if_request_matcher_matches(
121+
RequestMatcher $matcher,
122+
RequestInterface $request
123+
) {
124+
$matcher->matches($request)->willReturn(true);
125+
$this->on($matcher, new \Exception());
126+
$this->shouldThrow('Exception')->duringSendRequest($request);
127+
}
128+
129+
function it_skips_conditional_response_if_matcher_returns_false(
130+
RequestMatcher $matcher,
131+
RequestInterface $request,
132+
ResponseInterface $expectedResponse,
133+
ResponseInterface $skippedResponse
134+
) {
135+
$matcher->matches($request)->willReturn(false);
136+
$this->on($matcher, $skippedResponse);
137+
$this->addResponse($expectedResponse);
138+
$this->sendRequest($request)->shouldReturn($expectedResponse);
139+
}
140+
141+
function it_calls_callable_with_request_as_argument_when_matcher_returns_true(
142+
RequestMatcher $matcher,
143+
RequestInterface $request,
144+
ResponseInterface $response
145+
) {
146+
$matcher->matches($request)->willReturn(true);
147+
148+
$this->on(
149+
$matcher,
150+
function(RequestInterface $request) use ($response) {
151+
return $response->getWrappedObject();
152+
}
153+
);
154+
155+
$this->sendRequest($request)->shouldReturn($response);
156+
}
109157
}

src/Client.php

+63
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
use Http\Client\HttpAsyncClient;
99
use Http\Client\HttpClient;
1010
use Http\Discovery\MessageFactoryDiscovery;
11+
use Http\Message\RequestMatcher;
1112
use Http\Message\ResponseFactory;
13+
use Psr\Http\Client\ClientExceptionInterface;
1214
use Psr\Http\Message\RequestInterface;
1315
use Psr\Http\Message\ResponseInterface;
1416

@@ -30,6 +32,11 @@ class Client implements HttpClient, HttpAsyncClient
3032
*/
3133
private $responseFactory;
3234

35+
/**
36+
* @var array
37+
*/
38+
private $conditionalResults = [];
39+
3340
/**
3441
* @var RequestInterface[]
3542
*/
@@ -67,6 +74,22 @@ public function doSendRequest(RequestInterface $request)
6774
{
6875
$this->requests[] = $request;
6976

77+
foreach ($this->conditionalResults as $result) {
78+
/**
79+
* @var RequestMatcher
80+
*/
81+
$matcher = $result['matcher'];
82+
83+
/**
84+
* @var callable
85+
*/
86+
$callable = $result['callable'];
87+
88+
if ($matcher->matches($request)) {
89+
return $callable($request);
90+
}
91+
}
92+
7093
if (count($this->exceptions) > 0) {
7194
throw array_shift($this->exceptions);
7295
}
@@ -87,6 +110,46 @@ public function doSendRequest(RequestInterface $request)
87110
return $this->responseFactory->createResponse();
88111
}
89112

113+
/**
114+
* Adds an exception to be thrown or response to be returned if the request
115+
* matcher matches.
116+
*
117+
* For more complex logic, pass a callable as $result. The method is given
118+
* the request and MUST either return a ResponseInterface or throw an
119+
* exception that implements the PSR-18 / HTTPlug exception interface.
120+
*
121+
* @param ResponseInterface|Exception|ClientExceptionInterface|callable $result
122+
*/
123+
public function on(RequestMatcher $requestMatcher, $result)
124+
{
125+
$callable = null;
126+
127+
switch (true) {
128+
case is_callable($result):
129+
$callable = $result;
130+
131+
break;
132+
case $result instanceof ResponseInterface:
133+
$callable = function () use ($result) {
134+
return $result;
135+
};
136+
137+
break;
138+
case $result instanceof \Exception:
139+
$callable = function () use ($result) {
140+
throw $result;
141+
};
142+
143+
break;
144+
default:
145+
throw new \InvalidArgumentException('Result must be either a response, an exception, or a callable');
146+
}
147+
$this->conditionalResults[] = [
148+
'matcher' => $requestMatcher,
149+
'callable' => $callable,
150+
];
151+
}
152+
90153
/**
91154
* Adds an exception that will be thrown.
92155
*/

0 commit comments

Comments
 (0)