Skip to content

Commit cca92a9

Browse files
committed
Add HTTP status helper class
1 parent 2e79d09 commit cca92a9

File tree

3 files changed

+356
-0
lines changed

3 files changed

+356
-0
lines changed

src/Utility/HttpStatus.php

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
/**
3+
* Helper class for dealing with HTTP status codes.
4+
*
5+
* @package Requests\Utilities
6+
*/
7+
8+
namespace WpOrg\Requests\Utility;
9+
10+
use WpOrg\Requests\Exception\InvalidArgument;
11+
12+
/**
13+
* HTTP status codes helper class.
14+
*
15+
* @package Requests\Utilities
16+
*/
17+
final class HttpStatus {
18+
19+
const TEXT_100 = 'Continue';
20+
const TEXT_101 = 'Switching Protocols';
21+
const TEXT_200 = 'OK';
22+
const TEXT_201 = 'Created';
23+
const TEXT_202 = 'Accepted';
24+
const TEXT_203 = 'Non-Authoritative Information';
25+
const TEXT_204 = 'No Content';
26+
const TEXT_205 = 'Reset Content';
27+
const TEXT_206 = 'Partial Content';
28+
const TEXT_300 = 'Multiple Choices';
29+
const TEXT_301 = 'Moved Permanently';
30+
const TEXT_302 = 'Found';
31+
const TEXT_303 = 'See Other';
32+
const TEXT_304 = 'Not Modified';
33+
const TEXT_305 = 'Use Proxy';
34+
const TEXT_306 = '(Unused)';
35+
const TEXT_307 = 'Temporary Redirect';
36+
const TEXT_400 = 'Bad Request';
37+
const TEXT_401 = 'Unauthorized';
38+
const TEXT_402 = 'Payment Required';
39+
const TEXT_403 = 'Forbidden';
40+
const TEXT_404 = 'Not Found';
41+
const TEXT_405 = 'Method Not Allowed';
42+
const TEXT_406 = 'Not Acceptable';
43+
const TEXT_407 = 'Proxy Authentication Required';
44+
const TEXT_408 = 'Request Timeout';
45+
const TEXT_409 = 'Conflict';
46+
const TEXT_410 = 'Gone';
47+
const TEXT_411 = 'Length Required';
48+
const TEXT_412 = 'Precondition Failed';
49+
const TEXT_413 = 'Request Entity Too Large';
50+
const TEXT_414 = 'Request-URI Too Long';
51+
const TEXT_415 = 'Unsupported Media Type';
52+
const TEXT_416 = 'Requested Range Not Satisfiable';
53+
const TEXT_417 = 'Expectation Failed';
54+
const TEXT_418 = 'I\'m a teapot';
55+
const TEXT_428 = 'Precondition Required';
56+
const TEXT_429 = 'Too Many Requests';
57+
const TEXT_431 = 'Request Header Fields Too Large';
58+
const TEXT_500 = 'Internal Server Error';
59+
const TEXT_501 = 'Not Implemented';
60+
const TEXT_502 = 'Bad Gateway';
61+
const TEXT_503 = 'Service Unavailable';
62+
const TEXT_504 = 'Gateway Timeout';
63+
const TEXT_505 = 'HTTP Version Not Supported';
64+
const TEXT_511 = 'Network Authentication Required';
65+
66+
/**
67+
* Map of status codes to their text.
68+
*
69+
* @var array<string>
70+
*/
71+
const MAP = [
72+
100 => self::TEXT_100,
73+
101 => self::TEXT_101,
74+
200 => self::TEXT_200,
75+
201 => self::TEXT_201,
76+
202 => self::TEXT_202,
77+
203 => self::TEXT_203,
78+
204 => self::TEXT_204,
79+
205 => self::TEXT_205,
80+
206 => self::TEXT_206,
81+
300 => self::TEXT_300,
82+
301 => self::TEXT_301,
83+
302 => self::TEXT_302,
84+
303 => self::TEXT_303,
85+
304 => self::TEXT_304,
86+
305 => self::TEXT_305,
87+
306 => self::TEXT_306,
88+
307 => self::TEXT_307,
89+
400 => self::TEXT_400,
90+
401 => self::TEXT_401,
91+
402 => self::TEXT_402,
92+
403 => self::TEXT_403,
93+
404 => self::TEXT_404,
94+
405 => self::TEXT_405,
95+
406 => self::TEXT_406,
96+
407 => self::TEXT_407,
97+
408 => self::TEXT_408,
98+
409 => self::TEXT_409,
99+
410 => self::TEXT_410,
100+
411 => self::TEXT_411,
101+
412 => self::TEXT_412,
102+
413 => self::TEXT_413,
103+
414 => self::TEXT_414,
104+
415 => self::TEXT_415,
105+
416 => self::TEXT_416,
106+
417 => self::TEXT_417,
107+
418 => self::TEXT_418,
108+
428 => self::TEXT_428,
109+
429 => self::TEXT_429,
110+
431 => self::TEXT_431,
111+
500 => self::TEXT_500,
112+
501 => self::TEXT_501,
113+
502 => self::TEXT_502,
114+
503 => self::TEXT_503,
115+
504 => self::TEXT_504,
116+
505 => self::TEXT_505,
117+
511 => self::TEXT_511,
118+
];
119+
120+
/**
121+
* Get the status message from a status code.
122+
*
123+
* @param int|string $code Status code.
124+
* @return string Status message.
125+
*/
126+
public static function get_text($code) {
127+
if (self::is_valid_code($code) === false) {
128+
// When the type is correct, add the value to the error message to help debugging.
129+
$type = gettype($code) . ((is_int($code) || is_string($code)) ? " ($code)" : '');
130+
131+
throw InvalidArgument::create(1, '$code', 'a valid HTTP status code as an int or numeric string', $type);
132+
}
133+
134+
return self::MAP[$code];
135+
}
136+
137+
/**
138+
* Verify whether a status code is valid.
139+
*
140+
* @param int|string $code Status code to check.
141+
* @return bool Whether the status code is valid.
142+
*/
143+
public static function is_valid_code($code) {
144+
if (!is_int($code) && !is_string($code)) {
145+
return false;
146+
}
147+
148+
return array_key_exists($code, self::MAP);
149+
}
150+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
namespace WpOrg\Requests\Tests\Utility\HttpStatus;
4+
5+
use WpOrg\Requests\Exception;
6+
use WpOrg\Requests\Exception\InvalidArgument;
7+
use WpOrg\Requests\Tests\TestCase;
8+
use WpOrg\Requests\Tests\TypeProviderHelper;
9+
use WpOrg\Requests\Utility\HttpStatus;
10+
11+
/**
12+
* @coversDefaultClass \WpOrg\Requests\Utility\HttpStatus
13+
*/
14+
class GetTextTest extends TestCase {
15+
/**
16+
* Data provider.
17+
*
18+
* @return array
19+
*/
20+
public static function dataAccessValidEntry() {
21+
return [
22+
'integer key' => [404, 'Not Found'],
23+
'string key' => ['502', 'Bad Gateway'],
24+
];
25+
}
26+
27+
/**
28+
* Test retrieving a valid status code.
29+
*
30+
* @dataProvider dataAccessValidEntry
31+
*
32+
* @covers ::get_text
33+
*
34+
* @param mixed $code Status code value to test.
35+
*
36+
* @return void
37+
*/
38+
public function testAccessValidEntry($code, $text) {
39+
$this->assertSame($text, HttpStatus::get_text($code));
40+
}
41+
42+
/**
43+
* Data provider.
44+
*
45+
* @return array
46+
*/
47+
public static function dataAccessInvalidType() {
48+
return TypeProviderHelper::getAllExcept(TypeProviderHelper::GROUP_INT, TypeProviderHelper::GROUP_STRING);
49+
}
50+
51+
/**
52+
* Test retrieving a status code with an invalid type.
53+
*
54+
* @dataProvider dataAccessInvalidType
55+
*
56+
* @covers ::get_text
57+
*
58+
* @param mixed $code Status code value to test.
59+
*
60+
* @return void
61+
*/
62+
public function testAccessInvalidType($code) {
63+
$this->expectException(InvalidArgument::class);
64+
$this->expectExceptionMessage('a valid HTTP status code as an int or numeric string');
65+
HttpStatus::get_text($code);
66+
}
67+
68+
/**
69+
* Data provider.
70+
*
71+
* @return array
72+
*/
73+
public static function dataAccessInvalidCode() {
74+
return [
75+
'negative integer' => [-1],
76+
'zero integer' => [0],
77+
'too low integer' => [42],
78+
'too high integer' => [1000],
79+
'negative string' => ['-1'],
80+
'zero string' => ['0'],
81+
'too low string' => ['42'],
82+
'too high string' => ['1000'],
83+
];
84+
}
85+
86+
/**
87+
* Test retrieving a status code with a matching type but an invalid code.
88+
*
89+
* @dataProvider dataAccessInvalidCode
90+
*
91+
* @covers ::get_text
92+
*
93+
* @param mixed $code Status code value to test.
94+
*
95+
* @return void
96+
*/
97+
public function testAccessInvalidCode($code) {
98+
$this->expectException(InvalidArgument::class);
99+
$this->expectExceptionMessage(
100+
sprintf(
101+
'a valid HTTP status code as an int or numeric string, %s (%s) given',
102+
gettype($code),
103+
$code
104+
)
105+
);
106+
HttpStatus::get_text($code);
107+
}
108+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
namespace WpOrg\Requests\Tests\Utility\HttpStatus;
4+
5+
use WpOrg\Requests\Exception;
6+
use WpOrg\Requests\Exception\InvalidArgument;
7+
use WpOrg\Requests\Tests\TestCase;
8+
use WpOrg\Requests\Tests\TypeProviderHelper;
9+
use WpOrg\Requests\Utility\HttpStatus;
10+
11+
/**
12+
* @coversDefaultClass \WpOrg\Requests\Utility\HttpStatus
13+
*/
14+
class IsValidCodeTest extends TestCase {
15+
/**
16+
* Data provider.
17+
*
18+
* @return array
19+
*/
20+
public static function dataAccessValidEntry() {
21+
return [
22+
'integer key' => [404],
23+
'string key' => ['502'],
24+
];
25+
}
26+
27+
/**
28+
* Test a valid status code.
29+
*
30+
* @dataProvider dataAccessValidEntry
31+
*
32+
* @covers ::is_valid_code
33+
*
34+
* @param mixed $code Status code value to test.
35+
*
36+
* @return void
37+
*/
38+
public function testAccessValidEntry($code) {
39+
$this->assertTrue(HttpStatus::is_valid_code($code));
40+
}
41+
42+
/**
43+
* Data provider.
44+
*
45+
* @return array
46+
*/
47+
public static function dataAccessInvalidType() {
48+
return TypeProviderHelper::getAllExcept(TypeProviderHelper::GROUP_INT, TypeProviderHelper::GROUP_STRING);
49+
}
50+
51+
/**
52+
* Test retrieving a status code with an invalid type.
53+
*
54+
* @dataProvider dataAccessInvalidType
55+
*
56+
* @covers ::is_valid_code
57+
*
58+
* @param mixed $code Status code value to test.
59+
*
60+
* @return void
61+
*/
62+
public function testAccessInvalidType($code) {
63+
$this->assertFalse(HttpStatus::is_valid_code($code));
64+
}
65+
66+
/**
67+
* Data provider.
68+
*
69+
* @return array
70+
*/
71+
public static function dataAccessInvalidCode() {
72+
return [
73+
'negative integer' => [-1],
74+
'zero integer' => [0],
75+
'too low integer' => [42],
76+
'too high integer' => [1000],
77+
'negative string' => ['-1'],
78+
'zero string' => ['0'],
79+
'too low string' => ['42'],
80+
'too high string' => ['1000'],
81+
];
82+
}
83+
84+
/**
85+
* Test retrieving a status code with a matching type but an invalid code.
86+
*
87+
* @dataProvider dataAccessInvalidCode
88+
*
89+
* @covers ::is_valid_code
90+
*
91+
* @param mixed $code Status code value to test.
92+
*
93+
* @return void
94+
*/
95+
public function testAccessInvalidCode($code) {
96+
$this->assertFalse(HttpStatus::is_valid_code($code));
97+
}
98+
}

0 commit comments

Comments
 (0)