* @author Contributors of https://github.com/KnpLabs/php-github-api */ abstract class TestCase extends \PHPUnit\Framework\TestCase { private $requestMethod; private $requestUri; private $requestHeaders = []; private $requestBody; private $httpResponse; private $hydratedResponse; private $hydrateClass; protected function setUp(): void { $this->reset(); } abstract protected function getApiClass(); /** * This will give you a mocked API. Optionally you can provide mocked dependencies. */ protected function getApiMock($httpClient = null, $requestClient = null, $hydrator = null) { if (null === $httpClient) { $httpClient = $this->getMockBuilder(ClientInterface::class) ->setMethods(['sendRequest']) ->getMock(); $httpClient ->expects($this->any()) ->method('sendRequest'); } if (null === $requestClient) { $requestClient = $this->getMockBuilder('Mailgun\HttpClient\RequestBuilder') ->setMethods(['create']) ->getMock(); } if (null === $hydrator) { $hydrator = $this->getMockBuilder('Mailgun\Hydrator\Hydrator') ->setMethods(['hydrate']) ->getMock(); } return $this->getMockBuilder($this->getApiClass()) ->setMethods(['httpGet', 'httpPost', 'httpPostRaw', 'httpDelete', 'httpPut']) ->setConstructorArgs([$httpClient, $requestClient, $hydrator]) ->getMock(); } /** * This will return you a real API instance with mocked dependencies. * This will make use of the "setHydratedResponse" and "setRequestMethod" etc.. */ protected function getApiInstance($apiKey = null) { $httpClient = $this->getMockBuilder(ClientInterface::class) ->setMethods(['sendRequest']) ->getMock(); $httpClient ->method('sendRequest') ->willReturn(null === $this->httpResponse ? new Response() : $this->httpResponse); $requestClient = $this->getMockBuilder('Mailgun\HttpClient\RequestBuilder') ->setMethods(['create']) ->getMock(); if (null !== $this->requestMethod || null !== $this->requestUri || !empty($this->requestHeaders) || !empty($this->requestBody) ) { $requestClient ->expects($this->once()) ->method('create') ->with( $this->callback([$this, 'validateRequestMethod']), $this->callback([$this, 'validateRequestUri']), $this->callback([$this, 'validateRequestHeaders']), $this->callback([$this, 'validateRequestBody']) ) ->willReturn(new Request('GET', '/')); } $hydrator = new ModelHydrator(); if (null === $this->httpResponse) { $hydrator = $this->getMockBuilder('Mailgun\Hydrator\Hydrator') ->setMethods(['hydrate']) ->getMock(); $hydratorModelClass = $this->hydrateClass; $hydrateMethod = $hydrator->method('hydrate') ->with( $this->callback(function ($response) { return $response instanceof ResponseInterface; }), $this->callback(function ($class) use ($hydratorModelClass) { return null === $hydratorModelClass || $class === $hydratorModelClass; })); if (null !== $this->hydratedResponse) { $hydrateMethod->willReturn($this->hydratedResponse); } } $class = $this->getApiClass(); if (null !== $apiKey) { return new $class($httpClient, $requestClient, $hydrator, $apiKey); } return new $class($httpClient, $requestClient, $hydrator); } public function validateRequestMethod($method) { return $this->verifyProperty($this->requestMethod, $method); } public function validateRequestUri($uri) { return $this->verifyProperty($this->requestUri, $uri); } public function validateRequestHeaders($headers) { return $this->verifyProperty($this->requestHeaders, $headers); } public function validateRequestBody($body) { if ($this->verifyProperty($this->requestBody, $body)) { return true; } // Assert: $body is prepared for a "multipart stream". // Check length if (count($this->requestBody) !== count($body)) { return false; } // Check every item in body. foreach ($body as $item) { if ('resource' === $this->requestBody[$item['name']] && is_resource($item['content'])) { continue; } if ($this->requestBody[$item['name']] !== $item['content']) { return false; } } return true; } protected function reset() { $this->httpResponse = null; $this->hydratedResponse = null; $this->requestMethod = null; $this->requestUri = null; $this->requestHeaders = null; $this->requestBody = null; $this->hydrateClass = null; } /** * Set a response that you want to client to respond with. */ public function setHttpResponse(ResponseInterface $httpResponse) { $this->httpResponse = $httpResponse; } /** * The data you want the hydrator to return. */ public function setHydratedResponse($hydratedResponse) { $this->hydratedResponse = $hydratedResponse; } /** * Set request http method. */ public function setRequestMethod(string $httpMethod) { $this->requestMethod = $httpMethod; } public function setRequestUri(string $requestUri) { $this->requestUri = $requestUri; } public function setRequestHeaders(array $requestHeaders) { $this->requestHeaders = $requestHeaders; } public function setRequestBody($requestBody) { $this->requestBody = $requestBody; } /** * The class we should hydrate to. * * @param string $hydrateClass */ public function setHydrateClass($hydrateClass) { $this->hydrateClass = $hydrateClass; } /** * @param mixed|callable $property Example $this->requestMethod * @param mixed $value the actual value from the user * * @return bool */ private function verifyProperty($property, $value) { if (null === $property) { return true; } return is_callable($property) ? call_user_func($property, $value) : $value === $property; } }