Completed
Pull Request — master (#175)
by
unknown
02:09
created

shouldNotOutputBodyByResponseCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 6
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 10
rs 10
1
<?php
2
namespace Yiisoft\Yii\Web\Tests\Emitter;
3
4
include 'includeMocks.php';
5
6
use Nyholm\Psr7\Response;
7
use PHPUnit\Framework\TestCase;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\StreamInterface;
10
use Yiisoft\Yii\Web\Emitter\EmitterInterface;
11
use Yiisoft\Yii\Web\Emitter\SapiEmitter;
12
13
/**
14
 * @runTestsInSeparateProcesses
15
 */
16
class SapiEmitterTest extends TestCase
17
{
18
    public function setUp(): void
19
    {
20
        HTTPFunctions::reset();
21
    }
22
23
    public static function tearDownAfterClass(): void
24
    {
25
        HTTPFunctions::reset();
26
    }
27
28
    public function noBodyHTTPCodeProvider(): array
29
    {
30
        return [[100], [101], [102], [204], [205], [304]];
31
    }
32
33
    public function testHTTPFunctions(): void
34
    {
35
        // check default code 200, check hasHeader
36
        $this->assertEquals(200, $this->getResponseCode());
37
        $this->assertEquals([], $this->getHeaders());
38
        $this->assertFalse(HTTPFunctions::hasHeader('x-test'));
39
40
        // add header, check hasHeader
41
        HTTPFunctions::header('X-Test: 1');
42
        $this->assertTrue(HTTPFunctions::hasHeader('x-test'));
43
        $this->assertEquals(['X-Test: 1'], $this->getHeaders());
44
45
        // added header, change status
46
        HTTPFunctions::header('X-Test: 2', false, 300);
47
        $this->assertContains('X-Test: 1', $this->getHeaders());
48
        $this->assertContains('X-Test: 2', $this->getHeaders());
49
        $this->assertEquals(300, $this->getResponseCode());
50
51
        // replace x-test headers, change status
52
        HTTPFunctions::header('X-Test: 3', true, 404);
53
        HTTPFunctions::header('Control-Cache: no-cache');
54
        $this->assertCount(2, $this->getHeaders());
55
        $this->assertContains('X-Test: 3', $this->getHeaders());
56
        $this->assertContains('Control-Cache: no-cache', $this->getHeaders());
57
        $this->assertEquals(404, $this->getResponseCode());
58
59
        // remove x-test header
60
        HTTPFunctions::header_remove('x-test');
61
        $this->assertEquals(['Control-Cache: no-cache'], $this->getHeaders());
62
63
        // remove all headers and check code
64
        HTTPFunctions::header_remove();
65
        $this->assertEquals(404, $this->getResponseCode());
66
        $this->assertEquals([], $this->getHeaders());
67
68
        // check defaults after reset
69
        HTTPFunctions::header('X-Test: 3', true, 404);
70
        HTTPFunctions::reset();
71
        $this->assertEquals(200, $this->getResponseCode());
72
        $this->assertEquals([], $this->getHeaders());
73
    }
74
75
    public function testEmit(): void
76
    {
77
        $body = 'Example body';
78
        $response = $this->createResponse(200, ['X-Test' => 1], $body);
79
80
        $this->createEmitter()->emit($response);
81
82
        $this->assertEquals(200, $this->getResponseCode());
83
        $this->assertCount(2, $this->getHeaders());
84
        $this->assertContains('X-Test: 1', $this->getHeaders());
85
        $this->assertContains('Content-Length: ' . strlen($body), $this->getHeaders());
86
        $this->expectOutputString($body);
87
    }
88
89
    /**
90
     * @test
91
     * @dataProvider noBodyHTTPCodeProvider
92
     */
93
    public function shouldNotOutputBodyByResponseCode(int $code): void
94
    {
95
        $response = $this->createResponse($code, ['X-Test' => 1], 'Example body');
96
97
        $this->createEmitter()->emit($response);
98
99
        $this->assertEquals($code, $this->getResponseCode());
100
        $this->assertTrue(HTTPFunctions::hasHeader('X-Test'));
101
        $this->assertFalse(HTTPFunctions::hasHeader('Content-Length'));
102
        $this->expectOutputString('');
103
    }
104
105
    /**
106
     * @test
107
     */
108
    public function shouldNotOutputBodyAndContentLengthIfEmitToldSo(): void
109
    {
110
        $response = $this->createResponse(200, ['X-Test' => 1], 'Example body');
111
112
        $this->createEmitter()->emit($response, true);
113
114
        $this->assertEquals(200, $this->getResponseCode());
115
        $this->assertTrue(HTTPFunctions::hasHeader('X-Test'));
116
        $this->assertFalse(HTTPFunctions::hasHeader('Content-Length'));
117
        $this->expectOutputString('');
118
    }
119
120
    /**
121
     * @test
122
     */
123
    public function contentLengthShouldNotBeOverwrittenIfPresent(): void
124
    {
125
        $length = 100;
126
        $response = $this->createResponse(200, ['Content-Length' => $length, 'X-Test' => 1], 'Example body');
127
128
        $this->createEmitter()->emit($response);
129
130
        $this->assertEquals(200, $this->getResponseCode());
131
        $this->assertCount(2, $this->getHeaders());
132
        $this->assertContains('X-Test: 1', $this->getHeaders());
133
        $this->assertContains('Content-Length: ' . $length, $this->getHeaders());
134
        $this->expectOutputString('Example body');
135
    }
136
137
    /**
138
     * @test
139
     */
140
    public function contentLengthShouldNotOutputWhenBodyIsEmpty(): void
141
    {
142
        $length = 100;
143
        $response = $this->createResponse(200, ['Content-Length' => $length, 'X-Test' => 1], '');
144
145
        $this->createEmitter()->emit($response);
146
147
        $this->assertEquals(200, $this->getResponseCode());
148
        $this->assertEquals(['X-Test: 1'], $this->getHeaders());
149
        $this->expectOutputString('');
150
    }
151
152
    /**
153
     * @test
154
     */
155
    public function contentAlwaysShouldBeFullyEmitted(): void
156
    {
157
        $body = 'Example body';
158
        $response = $this->createResponse(200, ['Content-length' => 1, 'X-Test' => 1], $body);
159
160
        $this->createEmitter()->emit($response);
161
162
        $this->expectOutputString($body);
163
    }
164
165
    /**
166
     * @test
167
     */
168
    public function sentHeadersShouldBeRemoved(): void
169
    {
170
        HTTPFunctions::header('Cookie-Set: First Cookie');
171
        HTTPFunctions::header('X-Test: 1');
172
        $body = 'Example body';
173
        $response = $this->createResponse(200, [], $body);
174
175
        $this->createEmitter()->emit($response);
176
177
        $this->assertEquals(['Content-Length: ' . strlen($body)], $this->getHeaders());
178
        $this->expectOutputString($body);
179
    }
180
181
    /**
182
     * @test
183
     */
184
    public function emitDuplicatedHeaders(): void
185
    {
186
        $body = 'Example body';
187
        $response = $this->createResponse(200, [], $body)
188
                         ->withHeader('X-Test', '1')
189
                         ->withAddedHeader('X-Test', '2')
190
                         ->withAddedHeader('X-Test', '3; 3.5')
191
                         ->withHeader('Cookie-Set', '1')
192
                         ->withAddedHeader('cookie-Set', '2')
193
                         ->withAddedHeader('Cookie-set', '3');
194
195
        $this->createEmitter()->emit($response);
196
        $this->assertEquals(200, $this->getResponseCode());
197
        $this->assertContains('X-Test: 1', $this->getHeaders());
198
        $this->assertContains('X-Test: 2', $this->getHeaders());
199
        $this->assertContains('X-Test: 3; 3.5', $this->getHeaders());
200
        $this->assertContains('Cookie-Set: 1', $this->getHeaders());
201
        $this->assertContains('Cookie-Set: 2', $this->getHeaders());
202
        $this->assertContains('Cookie-Set: 3', $this->getHeaders());
203
        $this->assertContains('Content-Length: ' . strlen($body), $this->getHeaders());
204
        $this->expectOutputString($body);
205
    }
206
207
    private function createEmitter(?int $bufferSize = null): EmitterInterface
208
    {
209
        return new SapiEmitter($bufferSize);
210
    }
211
212
    private function createResponse(
213
        int $status = 200,
214
        array $headers = [],
215
        $body = null,
216
        string $version = '1.1'
217
    ): ResponseInterface {
218
        $response = (new Response())
219
            ->withStatus($status)
220
            ->withProtocolVersion($version);
221
        foreach ($headers as $header => $value) {
222
            $response = $response->withHeader($header, $value);
223
        }
224
        if ($body instanceof StreamInterface) {
225
            $response = $response->withBody($body);
226
        } elseif (is_string($body)) {
227
            $response->getBody()->write($body);
228
        }
229
        return $response;
230
    }
231
232
    private function getHeaders(): array
233
    {
234
        return HTTPFunctions::headers_list();
235
    }
236
237
    private function getResponseCode(): int
238
    {
239
        return HTTPFunctions::http_response_code();
240
    }
241
}
242