Skip to content

Commit 5fd85ab

Browse files
committed
test: introduce NativeHeadersStack utility for native header testing
1 parent 1bd1ca6 commit 5fd85ab

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Test\Utilities;
15+
16+
/**
17+
* Class NativeHeadersStack
18+
*
19+
* A utility class for simulating native PHP header handling in unit tests.
20+
* It allows the inspection, manipulation, and mocking of HTTP headers without
21+
* affecting the actual HTTP output.
22+
*
23+
* @internal This class is for testing purposes only.
24+
*/
25+
final class NativeHeadersStack
26+
{
27+
private static bool $headersSent = false;
28+
29+
/**
30+
* @var array<string, list<string>>
31+
*/
32+
private static array $headers = [];
33+
34+
private static ?int $responseCode = null;
35+
36+
/**
37+
* Resets the state of the class to its default values.
38+
*/
39+
public static function reset(): void
40+
{
41+
self::$headersSent = false;
42+
self::$headers = [];
43+
self::$responseCode = null;
44+
}
45+
46+
/**
47+
* Sets the state of whether headers have been sent.
48+
*/
49+
public static function setHeadersSent(bool $sent): void
50+
{
51+
self::$headersSent = $sent;
52+
}
53+
54+
/**
55+
* Simulates PHP's native `headers_sent()` function.
56+
*/
57+
public static function headersSent(): bool
58+
{
59+
return self::$headersSent;
60+
}
61+
62+
/**
63+
* Sets a header by name, replacing or appending it.
64+
* This is the main method for header manipulation.
65+
*
66+
* @param string $header The header string (e.g., 'Content-Type: application/json').
67+
* @param bool $replace Whether to replace a previous similar header.
68+
* @param int|null $responseCode Forces the HTTP response code to the specified value.
69+
*/
70+
public static function set(string $header, bool $replace = true, ?int $responseCode = null): void
71+
{
72+
if (str_contains($header, ':')) {
73+
[$name, $value] = explode(':', $header, 2);
74+
$name = trim($name);
75+
$value = trim($value);
76+
77+
if ($replace || ! isset(self::$headers[strtolower($name)])) {
78+
self::$headers[strtolower($name)] = [];
79+
}
80+
self::$headers[strtolower($name)][] = "{$name}: {$value}";
81+
} else {
82+
// Handle non-key-value headers like "HTTP/1.1 404 Not Found"
83+
self::$headers['status'][] = $header;
84+
}
85+
86+
if ($responseCode !== null) {
87+
self::$responseCode = $responseCode;
88+
}
89+
}
90+
91+
/**
92+
* Pushes a header to the stack without replacing existing ones.
93+
*/
94+
public static function push(string $header): void
95+
{
96+
self::set($header, false);
97+
}
98+
99+
/**
100+
* A convenience method to push multiple headers at once.
101+
*
102+
* @param list<string> $headers An array of headers to push onto the stack.
103+
*/
104+
public static function pushMany(array $headers): void
105+
{
106+
foreach ($headers as $header) {
107+
// Default to not replacing for multiple adds
108+
self::set($header, false);
109+
}
110+
}
111+
112+
/**
113+
* Simulates PHP's `headers_list()` function.
114+
*
115+
* @return list<string> The list of simulated headers.
116+
*/
117+
public static function listHeaders(): array
118+
{
119+
$list = [];
120+
121+
foreach (self::$headers as $values) {
122+
$list = array_merge($list, $values);
123+
}
124+
125+
return $list;
126+
}
127+
128+
/**
129+
* Checks if a header with the given name exists in the stack (case-insensitive).
130+
*
131+
* @param string $name The header name to search for (e.g., 'Content-Type').
132+
*/
133+
public static function hasHeader(string $name): bool
134+
{
135+
return isset(self::$headers[strtolower($name)]);
136+
}
137+
138+
/**
139+
* Simulates PHP's `http_response_code()` function.
140+
*
141+
* @return int|null The stored response code, or null if not set.
142+
*/
143+
public static function getResponseCode(): ?int
144+
{
145+
return self::$responseCode;
146+
}
147+
}

0 commit comments

Comments
 (0)