Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
AppTesting
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
4 / 4
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 suppressOutputBuffer
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 runCli
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 runHttp
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
9
1<?php declare(strict_types=1);
2/*
3 * This file is part of Aplus Framework Testing Library.
4 *
5 * (c) Natan Felles <natanfelles@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10namespace Framework\Testing;
11
12use Closure;
13use Framework\CLI\Streams\Stderr;
14use Framework\CLI\Streams\Stdout;
15use Framework\Config\Config;
16use Framework\HTTP\URL;
17use Framework\MVC\App;
18
19/**
20 * Class AppTesting.
21 *
22 * @package testing
23 */
24class AppTesting
25{
26    protected App $app;
27
28    /**
29     * AppTesting constructor.
30     *
31     * @param Config $config
32     */
33    public function __construct(Config $config)
34    {
35        $this->app = new class($config) extends App {
36            public function runCliWithExec(string $command) : void
37            {
38                $this->prepareToRun();
39                static::console()->exec($command);
40            }
41        };
42    }
43
44    /**
45     * Run App in a Closure suppressing the output buffer.
46     *
47     * It avoids buffer to be output in the PHPUnit terminal.
48     *
49     * @param Closure $closure
50     */
51    protected function suppressOutputBuffer(Closure $closure) : void
52    {
53        \ob_start(static function () {
54            return '';
55        });
56        $closure($this->app);
57        \ob_end_clean();
58    }
59
60    /**
61     * Simulate a CLI request for tests.
62     *
63     * @param string $command Command line
64     * @param array<string,string> $env Environment variables
65     *
66     * @return void
67     */
68    public function runCli(string $command, array $env = []) : void
69    {
70        App::setIsCli(true);
71        Stderr::init();
72        Stdout::init();
73        $this->suppressOutputBuffer(static function (App $app) use ($command) : void {
74            if ($command === '') {
75                $command = 'index';
76            }
77            $app->runCliWithExec($command); // @phpstan-ignore-line
78        });
79    }
80
81    /**
82     * Simulate an HTTP Request for tests.
83     *
84     * @param string|URL $url
85     * @param string $method
86     * @param array<string,string> $headers
87     * @param string $body
88     *
89     * @return void
90     */
91    public function runHttp(
92        URL | string $url,
93        string $method = 'GET',
94        array $headers = [],
95        string $body = ''
96    ) : void {
97        App::setIsCli(false);
98        if ( ! $url instanceof URL) {
99            $url = new URL($url);
100        }
101        $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
102        $_SERVER['REQUEST_METHOD'] = \strtoupper($method);
103        $_SERVER['REQUEST_SCHEME'] = $url->getScheme();
104        $_SERVER['HTTP_HOST'] = $url->getHost();
105        $query = $url->getQuery();
106        $query = $query === null ? '' : '?' . $query;
107        $_SERVER['REQUEST_URI'] = $url->getPath() . $query;
108        foreach ($headers as $name => $value) {
109            $name = \strtoupper($name);
110            $name = \strtr($name, ['-' => '_']);
111            $_SERVER['HTTP_' . $name] = $value;
112        }
113        if (isset($_SERVER['HTTP_COOKIE'])) {
114            $cookies = \explode(';', $_SERVER['HTTP_COOKIE']);
115            foreach ($cookies as $cookie) {
116                $cookie = \explode('=', $cookie, 2);
117                $cookie = \array_pad($cookie, 2, '');
118                $cookie[0] = \ltrim($cookie[0]);
119                $cookie[0] = \strtr($cookie[0], [' ' => '_']);
120                $_COOKIE[$cookie[0]] = $cookie[1];
121            }
122        }
123        $_GET = $url->getQueryData();
124        App::request()->setBody($body); // @phpstan-ignore-line
125        if ($_SERVER['REQUEST_METHOD'] === 'POST'
126            && isset($_SERVER['HTTP_CONTENT_TYPE'])
127            && $_SERVER['HTTP_CONTENT_TYPE'] === 'application/x-www-form-urlencoded'
128        ) {
129            \parse_str($body, $_POST);
130        }
131        $this->suppressOutputBuffer(static function (App $app) : void {
132            $app->runHttp();
133        });
134    }
135}