33namespace Sammyjo20 \Saloon \Clients ;
44
55use ReflectionClass ;
6- use Illuminate \ Support \ Str ;
6+ use Sammyjo20 \ Saloon \ Helpers \ URLHelper ;
77use Sammyjo20 \Saloon \Http \MockResponse ;
8+ use PHPUnit \Framework \Assert as PHPUnit ;
89use Sammyjo20 \Saloon \Http \SaloonRequest ;
10+ use Sammyjo20 \Saloon \Http \SaloonResponse ;
911use Sammyjo20 \Saloon \Http \SaloonConnector ;
12+ use Sammyjo20 \Saloon \Helpers \ReflectionHelper ;
1013use Sammyjo20 \Saloon \Exceptions \SaloonNoMockResponseFoundException ;
11- use Sammyjo20 \Saloon \Exceptions \SaloonNoMockResponsesProvidedException ;
1214use Sammyjo20 \Saloon \Exceptions \SaloonInvalidMockResponseCaptureMethodException ;
1315
1416class BaseMockClient
1517{
18+ /**
19+ * Collection of all the responses that will be sequenced.
20+ *
21+ * @var array
22+ */
1623 protected array $ sequenceResponses = [];
1724
25+ /**
26+ * Collection of responses used only when a connector is called.
27+ *
28+ * @var array
29+ */
1830 protected array $ connectorResponses = [];
1931
32+ /**
33+ * Collection of responses used only when a request is called.
34+ *
35+ * @var array
36+ */
2037 protected array $ requestResponses = [];
2138
39+ /**
40+ * Collection of responses that will run when the request is matched.
41+ *
42+ * @var array
43+ */
2244 protected array $ urlResponses = [];
2345
2446 /**
25- * @param array $responses
26- * @throws SaloonNoMockResponsesProvidedException
47+ * Collection of all the recorded responses.
48+ *
49+ * @var array
50+ */
51+ protected array $ recordedResponses = [];
52+
53+ /**
54+ * @param array $mockData
55+ * @throws SaloonInvalidMockResponseCaptureMethodException
2756 */
2857 public function __construct (array $ mockData = [])
2958 {
@@ -48,6 +77,14 @@ public function addResponses(array $responses): void
4877 }
4978 }
5079
80+ /**
81+ * Add a mock response to the client
82+ *
83+ * @param MockResponse $response
84+ * @param string|null $captureMethod
85+ * @return void
86+ * @throws SaloonInvalidMockResponseCaptureMethodException
87+ */
5188 public function addResponse (MockResponse $ response , ?string $ captureMethod = null ): void
5289 {
5390 if (is_null ($ captureMethod )) {
@@ -84,6 +121,11 @@ public function addResponse(MockResponse $response, ?string $captureMethod = nul
84121 $ this ->urlResponses [$ captureMethod ] = $ response ;
85122 }
86123
124+ /**
125+ * Get the next response in the sequence
126+ *
127+ * @return mixed
128+ */
87129 public function getNextFromSequence (): mixed
88130 {
89131 return array_shift ($ this ->sequenceResponses );
@@ -134,7 +176,7 @@ public function guessNextResponse(SaloonRequest $request): MockResponse
134176 private function guessResponseFromUrl (SaloonRequest $ request ): ?MockResponse
135177 {
136178 foreach ($ this ->urlResponses as $ url => $ response ) {
137- if (! Str:: is (Str:: start ( $ url, ' * ' ) , $ request ->getFullRequestUrl ())) {
179+ if (! URLHelper:: matches ( $ url , $ request ->getFullRequestUrl ())) {
138180 continue ;
139181 }
140182
@@ -153,4 +195,208 @@ public function isEmpty(): bool
153195 {
154196 return empty ($ this ->sequenceResponses ) && empty ($ this ->connectorResponses ) && empty ($ this ->requestResponses ) && empty ($ this ->urlResponses );
155197 }
198+
199+ /**
200+ * Record a response.
201+ *
202+ * @param SaloonResponse $response
203+ * @return void
204+ */
205+ public function recordResponse (SaloonResponse $ response ): void
206+ {
207+ $ this ->recordedResponses [] = $ response ;
208+ }
209+
210+ /**
211+ * Get all the recorded responses
212+ *
213+ * @return array
214+ */
215+ public function getRecordedResponses (): array
216+ {
217+ return $ this ->recordedResponses ;
218+ }
219+
220+ /**
221+ * Get the last request that the mock manager sent.
222+ *
223+ * @return SaloonRequest|null
224+ */
225+ public function getLastRequest (): ?SaloonRequest
226+ {
227+ return $ this ->getLastResponse ()?->getOriginalRequest();
228+ }
229+
230+ /**
231+ * Get the last response that the mock manager sent.
232+ *
233+ * @return SaloonResponse|null
234+ */
235+ public function getLastResponse (): ?SaloonResponse
236+ {
237+ if (empty ($ this ->recordedResponses )) {
238+ return null ;
239+ }
240+
241+ $ lastResponse = end ($ this ->recordedResponses );
242+
243+ reset ($ this ->recordedResponses );
244+
245+ return $ lastResponse ;
246+ }
247+
248+ /**
249+ * Assert that a given request was sent.
250+ *
251+ * @param string|callable $value
252+ * @return void
253+ * @throws \ReflectionException
254+ */
255+ public function assertSent (string |callable $ value ): void
256+ {
257+ $ result = $ this ->checkRequestWasSent ($ value );
258+
259+ PHPUnit::assertTrue ($ result , 'An expected request was not sent. ' );
260+ }
261+
262+ /**
263+ * Assert that a given request was not sent.
264+ *
265+ * @param string|callable $request
266+ * @return void
267+ * @throws \ReflectionException
268+ */
269+ public function assertNotSent (string |callable $ request ): void
270+ {
271+ $ result = $ this ->checkRequestWasNotSent ($ request );
272+
273+ PHPUnit::assertTrue ($ result , 'An unexpected request was sent. ' );
274+ }
275+
276+ /**
277+ * Assert JSON data was sent
278+ *
279+ * @param string $request
280+ * @param array $data
281+ * @return void
282+ * @throws \ReflectionException
283+ */
284+ public function assertSentJson (string $ request , array $ data ): void
285+ {
286+ $ this ->assertSent ($ request );
287+
288+ $ response = $ this ->findResponseByRequest ($ request );
289+
290+ PHPUnit::assertEquals ($ response ->json (), $ data , 'Expected request data was not sent. ' );
291+ }
292+
293+ /**
294+ * Assert that nothing was sent.
295+ *
296+ * @return void
297+ */
298+ public function assertNothingSent (): void
299+ {
300+ PHPUnit::assertEmpty ($ this ->getRecordedResponses (), 'Requests were sent. ' );
301+ }
302+
303+ /**
304+ * Assert a request count has been met.
305+ *
306+ * @param int $count
307+ * @return void
308+ */
309+ public function assertSentCount (int $ count ): void
310+ {
311+ PHPUnit::assertCount ($ count , $ this ->getRecordedResponses ());
312+ }
313+
314+ /**
315+ * Check if a given request was sent
316+ *
317+ * @param string|callable $request
318+ * @return bool
319+ * @throws \ReflectionException
320+ * @throws \Sammyjo20\Saloon\Exceptions\SaloonInvalidConnectorException
321+ */
322+ protected function checkRequestWasSent (string |callable $ request ): bool
323+ {
324+ $ result = false ;
325+
326+ if (is_callable ($ request )) {
327+ $ result = $ request ($ this ->getLastRequest (), $ this ->getLastResponse ());
328+ }
329+
330+ if (is_string ($ request )) {
331+ if (class_exists ($ request ) && ReflectionHelper::isSubclassOf ($ request , SaloonRequest::class)) {
332+ $ result = $ this ->findResponseByRequest ($ request ) instanceof SaloonResponse;
333+ } else {
334+ $ result = $ this ->findResponseByRequestUrl ($ request ) instanceof SaloonResponse;
335+ }
336+ }
337+
338+ return $ result ;
339+ }
340+
341+ /**
342+ * Check if a request has not been sent.
343+ *
344+ * @param string|callable $request
345+ * @return bool
346+ * @throws \ReflectionException
347+ * @throws \Sammyjo20\Saloon\Exceptions\SaloonInvalidConnectorException
348+ */
349+ protected function checkRequestWasNotSent (string |callable $ request ): bool
350+ {
351+ return ! $ this ->checkRequestWasSent ($ request );
352+ }
353+
354+ /**
355+ * Assert a given request was sent.
356+ *
357+ * @param string $request
358+ * @return SaloonResponse|null
359+ */
360+ public function findResponseByRequest (string $ request ): ?SaloonResponse
361+ {
362+ $ lastRequest = $ this ->getLastRequest ();
363+
364+ if ($ lastRequest instanceof $ request ) {
365+ return $ this ->getLastResponse ();
366+ }
367+
368+ foreach ($ this ->getRecordedResponses () as $ recordedResponse ) {
369+ if ($ recordedResponse ->getOriginalRequest () instanceof $ request ) {
370+ return $ recordedResponse ;
371+ }
372+ }
373+
374+ return null ;
375+ }
376+
377+ /**
378+ * Find a request that matches a given url pattern
379+ *
380+ * @param string $url
381+ * @return SaloonResponse|null
382+ * @throws \Sammyjo20\Saloon\Exceptions\SaloonInvalidConnectorException
383+ */
384+ public function findResponseByRequestUrl (string $ url ): ?SaloonResponse
385+ {
386+ $ lastRequest = $ this ->getLastRequest ();
387+
388+ if ($ lastRequest instanceof SaloonRequest && URLHelper::matches ($ url , $ lastRequest ->getFullRequestUrl ())) {
389+ return $ this ->getLastResponse ();
390+ }
391+
392+ foreach ($ this ->getRecordedResponses () as $ recordedResponse ) {
393+ $ request = $ recordedResponse ->getOriginalRequest ();
394+
395+ if (URLHelper::matches ($ url , $ request ->getFullRequestUrl ())) {
396+ return $ recordedResponse ;
397+ }
398+ }
399+
400+ return null ;
401+ }
156402}
0 commit comments