Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.29% covered (success)
95.29%
81 / 85
80.00% covered (warning)
80.00%
8 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Base
95.29% covered (success)
95.29%
81 / 85
80.00% covered (warning)
80.00%
8 / 10
35
0.00% covered (danger)
0.00%
0 / 1
 getSessionData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRequest
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 createBasicRequest
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
4.00
 getResponse
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 testRendering
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getControllerIdentifier
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 render
81.25% covered (warning)
81.25%
13 / 16
0.00% covered (danger)
0.00%
0 / 1
6.24
 setRequestParameters
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
10
 setValidatorInstance
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 assertRedirect
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
5 **/
6
7namespace BO\Slim\PhpUnit;
8
9use App;
10use BO\Slim\Middleware\Validator;
11use PHPUnit\Framework\TestCase;
12use BO\Slim\Middleware\SessionMiddleware;
13use BO\Slim\Middleware\Session\SessionHuman;
14use BO\Slim\Middleware\Session\SessionData;
15use Psr\Http\Message\ServerRequestInterface;
16use Psr\Http\Message\ResponseInterface;
17use Slim\Psr7\Environment;
18use Slim\Psr7\Factory\UriFactory;
19use Slim\Psr7\Headers;
20use BO\Slim\Request;
21use BO\Slim\Response;
22use Slim\Psr7\Factory\StreamFactory;
23
24/**
25 * @SuppressWarnings(PHPMD)
26 */
27abstract class Base extends TestCase
28{
29    /**
30      * Arguments for callback render
31      *
32      * @var array $arguments
33      */
34    protected $arguments = [];
35
36    /**
37      * Parameters for the request
38      *
39      * @var array $parameters
40      */
41    protected $parameters = [];
42
43    /**
44      * Data for the session
45      *
46      * @var array $sessionData
47      */
48    protected $sessionData = [];
49
50    /**
51     * Use this object instance for session getEntity()
52     *
53     * @var object|null
54     */
55    protected $sessionClass = null;
56
57    /**
58     * Namespace for tested classes
59     *
60     * @var string
61     */
62    protected $namespace = '';
63
64    /**
65     * A class name if not detected automatically
66     *
67     * @var string|null
68     */
69    protected $classname = null;
70
71    /**
72     * Overwrite this function if session data needs function calls
73     *
74     */
75    protected function getSessionData(): array
76    {
77        return $this->sessionData;
78    }
79
80    /**
81     *
82     * @param string $method
83     * @param string $uri
84     * @param array|null $sessionData
85     *
86     * @return ServerRequestInterface
87     */
88    protected function getRequest(
89        string $method = 'GET',
90        string $uri = '',
91        ?array $sessionData = null
92    ): ServerRequestInterface {
93        if (null === $sessionData) {
94            $sessionData = $this->getSessionData();
95        }
96        if (array_key_exists('human', $sessionData) && array_key_exists('ts', $sessionData['human'])) {
97            // prevent isOveraged error-Handling
98            $sessionData['human']['ts'] = time() - 10;
99        }
100        $request = self::createBasicRequest($method, $uri, ['Accept' => \BO\Slim\Headers::MEDIA_TYPE_TEXT_HTML]);
101        $sessionContainer = SessionHuman::fromContainer(function () use ($sessionData) {
102            $session = new SessionData($sessionData);
103            $session->setEntityClass($this->sessionClass);
104            return $session;
105        });
106
107        return $request->withAttribute(SessionMiddleware::SESSION_ATTRIBUTE, $sessionContainer);
108    }
109
110    /**
111     * Create a simple basic request
112     *
113     * @param string $method
114     * @param string $uri
115     * @return ServerRequestInterface
116     */
117    public static function createBasicRequest(
118        string $method = "GET",
119        string $uri = '',
120        array $addHeaders = []
121    ): ServerRequestInterface {
122        $env = Environment::mock([
123            'REQUEST_METHOD'       => $method,
124            'REQUEST_URI'          => $uri,
125            'REMOTE_ADDR'          => '127.0.0.1'
126        ]);
127
128        /** @psalm-suppress InternalMethod Slim's URI factory from mocked env is the supported test setup. */
129        $uri = (new UriFactory())->createFromGlobals($env);
130        $headers = Headers::createFromGlobals();
131        foreach ($addHeaders as $key => $value) {
132            $headers->addHeader($key, $value);
133        }
134
135        $body = (new StreamFactory())->createStream();
136
137        $request = new Request($method, $uri, $headers, [], $env, $body, []);
138
139        if (
140            $method === 'POST' &&
141            in_array($headers->getHeader('Content-Type'), ['application/x-www-form-urlencoded', 'multipart/form-data'])
142        ) {
143            // parsed body must be $_POST
144            $request = $request->withParsedBody($_POST);
145        }
146
147        return $request->withAttribute('ip_address', '127.0.0.1');
148    }
149
150    protected function getResponse(string $content = '', int $status = 200, array $headers = []): ResponseInterface
151    {
152        $body = (new StreamFactory())->createStream();
153        $headers = new Headers($headers);
154        $response = new Response($status, $headers, $body);
155        $body->write($content);
156        return $response;
157    }
158
159    /**
160     * @return ResponseInterface
161     */
162    public function testRendering()
163    {
164        $response = $this->render($this->arguments, $this->parameters);
165        $this->assertEquals(200, $response->getStatuscode());
166        return $response;
167    }
168
169    protected function getControllerIdentifier(): string
170    {
171        if ($this->classname !== null && $this->classname !== '') {
172            $classname = $this->classname;
173        } else {
174            $classname = preg_replace('#^.*?(\w+)Test$#', '$1', get_class($this));
175            $classname = is_string($classname) ? $classname : '';
176        }
177
178        return str_contains($classname, '\\') ? $classname : $this->namespace . $classname;
179    }
180
181    protected function render(
182        array $arguments = [],
183        array $parameters = [],
184        ?array $sessionData = null,
185        string $method = 'GET'
186    ): ResponseInterface {
187        $renderClass = $this->getControllerIdentifier();
188        if (!class_exists($renderClass)) {
189            throw new \RuntimeException('Controller class ' . $renderClass . ' does not exist');
190        }
191        $container = App::$slim->getContainer();
192        if (!$container instanceof \Psr\Container\ContainerInterface) {
193            throw new \RuntimeException('Slim container is not initialized');
194        }
195        /** @var \BO\Slim\Controller $controller */
196        /** @psalm-suppress UnsafeInstantiation */
197        $controller = new $renderClass($container);
198
199        //add uri to test multi languages
200        $uri = (isset($parameters['__uri']) && is_string($parameters['__uri'])) ? $parameters['__uri'] : '';
201        $request = $this->getRequest($method, $uri, $sessionData);
202        $request = $this->setRequestParameters($request, $parameters, $method);
203        $this->setValidatorInstance($parameters);
204        $request = Validator::withValidator($request);
205
206        $response = $controller->__invoke($request, $this->getResponse(), $arguments);
207        if (!$response instanceof ResponseInterface) {
208            throw new \RuntimeException('Controller did not return a PSR-7 response');
209        }
210        return $response;
211    }
212
213    protected function setRequestParameters(
214        ServerRequestInterface $request,
215        array $parameters,
216        string $method
217    ): ServerRequestInterface {
218        if ('GET' === $method) {
219            $request = $request->withQueryParams($parameters);
220        } elseif ('POST' === $method) {
221            $request = $request->withParsedBody($parameters);
222        }
223        if (array_key_exists('__body', $parameters)) {
224            $body = (new StreamFactory())->createStream();
225            $body->write($parameters['__body']);
226            $request = $request->withBody($body);
227        }
228        if (array_key_exists('__cookie', $parameters)) {
229            $request = $request->withCookieParams($parameters['__cookie']);
230        }
231        if (array_key_exists('__file', $parameters)) {
232            $request = $request->withUploadedFiles($parameters['__file']);
233        }
234        if (array_key_exists('__header', $parameters)) {
235            foreach ($parameters['__header'] as $key => $value) {
236                $request = $request->withAddedHeader($key, $value);
237            }
238        }
239        if (array_key_exists('__userinfo', $parameters)) {
240            $request = $request->withUri($request->getUri()->withUserInfo(
241                $parameters['__userinfo']['username'],
242                $parameters['__userinfo']['password']
243            ));
244        }
245        if (array_key_exists('__route', $parameters)) {
246            $request = $request->withAttribute('route', $parameters['__route']);
247        }
248
249        return $request;
250    }
251
252    protected function setValidatorInstance(array $parameters): void
253    {
254        $validator = new \BO\Mellon\Validator($parameters);
255        if (array_key_exists('__body', $parameters)) {
256            $validator->setInput($parameters['__body']);
257        }
258        $validator->makeInstance();
259    }
260
261    public function assertRedirect(ResponseInterface $response, string $uri, int $status = 302): void
262    {
263        $this->assertEquals($status, $response->getStatusCode());
264        $this->assertEquals($uri, $response->getHeaderLine('Location'));
265    }
266}