Passed
Pull Request — master (#216)
by
unknown
24:00 queued 01:45
created

testShouldNotOutputBodyByResponseCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Yiisoft\Yii\Web\Tests\Emitter;
4
5
include 'httpFunctionMocks.php';
6
7
use Nyholm\Psr7\Response;
8
use PHPUnit\Framework\TestCase;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\StreamInterface;
11
use Yiisoft\Yii\Web\Emitter\EmitterInterface;
12
use Yiisoft\Yii\Web\Emitter\SapiEmitter;
13
use Yiisoft\Yii\Web\Exception\HeadersHaveBeenSentException;
14
15
/**
16
 * @runTestsInSeparateProcesses
17
 * @preserveGlobalState disabled
18
 */
19
class SapiEmitterTest extends TestCase
20
{
21
    public function setUp(): void
22
    {
23
        HTTPFunctions::reset();
24
    }
25
26
    public static function tearDownAfterClass(): void
27
    {
28
        HTTPFunctions::reset();
29
    }
30
31
    public function noBodyHTTPCodeProvider(): array
32
    {
33
        return [[100], [101], [102], [204], [205], [304]];
34
    }
35
36
    public function testEmit(): void
37
    {
38
        $body = 'Example body';
39
        $response = $this->createResponse(200, ['X-Test' => 1], $body);
40
41
        $this->createEmitter()->emit($response);
42
43
        $this->assertEquals(200, $this->getResponseCode());
44
        $this->assertCount(2, $this->getHeaders());
45
        $this->assertContains('X-Test: 1', $this->getHeaders());
46
        $this->assertContains('Content-Length: ' . strlen($body), $this->getHeaders());
47
        $this->expectOutputString($body);
48
    }
49
50
    /**
51
     * @dataProvider noBodyHTTPCodeProvider
52
     */
53
    public function testShouldNotOutputBodyByResponseCode(int $code): void
54
    {
55
        $response = $this->createResponse($code, ['X-Test' => 1], 'Example body');
56
57
        $this->createEmitter()->emit($response);
58
59
        $this->assertEquals($code, $this->getResponseCode());
60
        $this->assertTrue(HTTPFunctions::hasHeader('X-Test'));
61
        $this->assertFalse(HTTPFunctions::hasHeader('Content-Length'));
62
        $this->expectOutputString('');
63
    }
64
65
    public function testShouldNotOutputBodyAndContentLengthIfEmitToldSo(): void
66
    {
67
        $response = $this->createResponse(200, ['X-Test' => 1], 'Example body');
68
69
        $this->createEmitter()->emit($response, true);
70
71
        $this->assertEquals(200, $this->getResponseCode());
72
        $this->assertTrue(HTTPFunctions::hasHeader('X-Test'));
73
        $this->assertFalse(HTTPFunctions::hasHeader('Content-Length'));
74
        $this->expectOutputString('');
75
    }
76
77
    public function testContentLengthShouldNotBeOverwrittenIfPresent(): void
78
    {
79
        $length = 100;
80
        $response = $this->createResponse(200, ['Content-Length' => $length, 'X-Test' => 1], 'Example body');
81
82
        $this->createEmitter()->emit($response);
83
84
        $this->assertEquals(200, $this->getResponseCode());
85
        $this->assertCount(2, $this->getHeaders());
86
        $this->assertContains('X-Test: 1', $this->getHeaders());
87
        $this->assertContains('Content-Length: ' . $length, $this->getHeaders());
88
        $this->expectOutputString('Example body');
89
    }
90
91
    public function testContentLengthShouldNotOutputWhenBodyIsEmpty(): void
92
    {
93
        $length = 100;
94
        $response = $this->createResponse(200, ['Content-Length' => $length, 'X-Test' => 1], '');
95
96
        $this->createEmitter()->emit($response);
97
98
        $this->assertEquals(200, $this->getResponseCode());
99
        $this->assertEquals(['X-Test: 1'], $this->getHeaders());
100
        $this->expectOutputString('');
101
    }
102
103
    public function testContentAlwaysShouldBeFullyEmitted(): void
104
    {
105
        $body = 'Example body';
106
        $response = $this->createResponse(200, ['Content-length' => 1, 'X-Test' => 1], $body);
107
108
        $this->createEmitter()->emit($response);
109
110
        $this->expectOutputString($body);
111
    }
112
113
    public function testSentHeadersShouldBeRemoved(): void
114
    {
115
        HTTPFunctions::header('Cookie-Set: First Cookie');
116
        HTTPFunctions::header('X-Test: 1');
117
        $body = 'Example body';
118
        $response = $this->createResponse(200, [], $body);
119
120
        $this->createEmitter()->emit($response);
121
122
        $this->assertEquals(['Content-Length: ' . strlen($body)], $this->getHeaders());
123
        $this->expectOutputString($body);
124
    }
125
126
    public function testExceptionWhenHeadersHaveBeenSent(): void
127
    {
128
        $body = 'Example body';
129
        $response = $this->createResponse(200, [], $body);
130
        HTTPFunctions::set_headers_sent(true, 'test-file.php', 200);
131
132
        $this->expectException(HeadersHaveBeenSentException::class);
133
        $this->createEmitter()->emit($response);
134
    }
135
136
    public function testShouldEmitDuplicateHeaders(): void
137
    {
138
        $body = 'Example body';
139
        $response = $this->createResponse(200, [], $body)
140
                         ->withHeader('X-Test', '1')
141
                         ->withAddedHeader('X-Test', '2')
142
                         ->withAddedHeader('X-Test', '3; 3.5')
143
                         ->withHeader('Cookie-Set', '1')
144
                         ->withAddedHeader('cookie-Set', '2')
145
                         ->withAddedHeader('Cookie-set', '3');
146
147
        $this->createEmitter()->emit($response);
148
        $this->assertEquals(200, $this->getResponseCode());
149
        $this->assertContains('X-Test: 1', $this->getHeaders());
150
        $this->assertContains('X-Test: 2', $this->getHeaders());
151
        $this->assertContains('X-Test: 3; 3.5', $this->getHeaders());
152
        $this->assertContains('Cookie-Set: 1', $this->getHeaders());
153
        $this->assertContains('Cookie-Set: 2', $this->getHeaders());
154
        $this->assertContains('Cookie-Set: 3', $this->getHeaders());
155
        $this->assertContains('Content-Length: ' . strlen($body), $this->getHeaders());
156
        $this->expectOutputString($body);
157
    }
158
159
    private function createEmitter(?int $bufferSize = null): EmitterInterface
160
    {
161
        return new SapiEmitter($bufferSize);
162
    }
163
164
    private function createResponse(
165
        int $status = 200,
166
        array $headers = [],
167
        $body = null,
168
        string $version = '1.1'
169
    ): ResponseInterface {
170
        $response = (new Response())
171
            ->withStatus($status)
172
            ->withProtocolVersion($version);
173
        foreach ($headers as $header => $value) {
174
            $response = $response->withHeader($header, $value);
175
        }
176
        if ($body instanceof StreamInterface) {
177
            $response = $response->withBody($body);
178
        } elseif (is_string($body)) {
179
            $response->getBody()->write($body);
180
        }
181
        return $response;
182
    }
183
184
    private function getHeaders(): array
185
    {
186
        return HTTPFunctions::headers_list();
187
    }
188
189
    private function getResponseCode(): int
190
    {
191
        return HTTPFunctions::http_response_code();
192
    }
193
}
194