-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add HTTP Request class and Unit Tests
- Implemented `Request` class under the `Atproto\HTTP` namespace with methods to manage URL, path, method, headers, parameters, and query parameters. - Added flexibility in setting and retrieving values for headers, parameters, and query parameters. - Provided encoding for headers and parameters as arrays or JSON. - Created `RequestTest` class under `Tests\Unit\HTTP` to ensure proper functionality: - Added tests for setting and retrieving values via the methods. - Verified instance return consistency when setting values. - Tested encoding output for headers, parameters, and query parameters.
- Loading branch information
1 parent
73358db
commit 16b2279
Showing
2 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
<?php | ||
|
||
namespace Atproto\HTTP; | ||
|
||
class Request | ||
{ | ||
protected string $url = ''; | ||
protected string $path = ''; | ||
protected string $method = 'GET'; | ||
protected array $headers = []; | ||
protected array $parameters = []; | ||
protected array $queryParameters = []; | ||
|
||
public function url(string $url = null) | ||
{ | ||
if (is_null($url)) { | ||
return $this->url; | ||
} | ||
|
||
$this->url = $url; | ||
|
||
return $this; | ||
} | ||
|
||
public function path(string $path = null) | ||
{ | ||
if (is_null($path)) { | ||
return $this->path; | ||
} | ||
|
||
$this->path = $path; | ||
|
||
return $this; | ||
} | ||
|
||
public function method(string $method = null) | ||
{ | ||
if (is_null($method)) { | ||
return $this->method; | ||
} | ||
|
||
$this->method = $method; | ||
|
||
return $this; | ||
} | ||
|
||
public function header(string $name, string $value = null) | ||
{ | ||
if (is_null($value)) { | ||
return $this->headers[$name] ?? null; | ||
} | ||
|
||
$this->headers[$name] = $value; | ||
|
||
return $this; | ||
} | ||
|
||
public function parameter(string $name, string $value = null) | ||
{ | ||
if (is_null($value)) { | ||
return $this->parameters[$name] ?? null; | ||
} | ||
|
||
$this->parameters[$name] = $value; | ||
|
||
return $this; | ||
} | ||
|
||
public function queryParameter(string $name, string $value = null) | ||
{ | ||
if (is_null($value)) { | ||
return $this->queryParameters[$name] ?? null; | ||
} | ||
|
||
$this->queryParameters[$name] = $value; | ||
|
||
return $this; | ||
} | ||
|
||
public function headers($headers = null) | ||
{ | ||
if (is_bool($headers) && $headers) { | ||
return array_map( | ||
fn ($name, $value) => "$name: $value", | ||
array_keys($this->headers), | ||
array_values($this->headers) | ||
); | ||
} | ||
|
||
if (is_null($headers)) { | ||
return $this->headers; | ||
} | ||
|
||
$this->headers = $headers; | ||
|
||
return $this; | ||
} | ||
|
||
public function parameters($parameters = null) | ||
{ | ||
if (is_bool($parameters) && $parameters) { | ||
return json_encode($this->parameters); | ||
} | ||
|
||
if (is_null($parameters)) { | ||
return $this->parameters; | ||
} | ||
|
||
$this->parameters = $parameters; | ||
|
||
return $this; | ||
} | ||
|
||
public function queryParameters($queryParameters = null) | ||
{ | ||
if (is_bool($queryParameters) && $queryParameters) { | ||
return http_build_query($this->queryParameters); | ||
} | ||
|
||
if (is_null($queryParameters)) { | ||
return $this->queryParameters; | ||
} | ||
|
||
$this->queryParameters = $queryParameters; | ||
|
||
return $this; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
<?php | ||
|
||
namespace Tests\Unit\HTTP; | ||
|
||
use ArgumentCountError; | ||
use Atproto\HTTP\Request; | ||
use Faker\Factory; | ||
use Faker\Generator; | ||
use PHPUnit\Framework\TestCase; | ||
use ReflectionClass; | ||
use ReflectionProperty; | ||
use TypeError; | ||
|
||
class RequestTest extends TestCase | ||
{ | ||
protected Request $request; | ||
protected Generator $faker; | ||
|
||
protected function setUp(): void | ||
{ | ||
$this->request = new Request(); | ||
$this->faker = Factory::create(); | ||
} | ||
|
||
/** @dataProvider methodProvider */ | ||
public function testMethodSetsCorrectValue(string $method, string $property): void | ||
{ | ||
$key = $this->faker->word; | ||
$expected = $this->faker->word; | ||
|
||
try { | ||
$reflectedProperty = $this->getPropertyValue($property); | ||
|
||
$value = (is_array($reflectedProperty)) | ||
? [$key => $expected] | ||
: $expected; | ||
|
||
$this->request->$method($value); | ||
} catch (TypeError $e) { | ||
$this->request->$method($key, $expected); | ||
} | ||
|
||
$actual = $this->getPropertyValue($property); | ||
|
||
if (is_array($actual)) { | ||
$this->assertArrayHasKey($key, $actual); | ||
$actual = $actual[$key]; | ||
} | ||
|
||
$this->assertSame($expected, $actual); | ||
} | ||
|
||
/** @dataProvider methodProvider */ | ||
public function testMethodReturnsCorrectValue(string $method, string $property): void | ||
{ | ||
$key = $this->faker->word; | ||
$expected = $this->faker->word; | ||
|
||
$propertyValue = $this->getPropertyValue($property); | ||
|
||
if (is_array($propertyValue)) { | ||
$expected = [$key => $expected]; | ||
} | ||
|
||
$this->setPropertyValue($property, $expected); | ||
|
||
try { | ||
$actual = $this->request->$method(); | ||
} catch (ArgumentCountError $e) { | ||
$actual = $this->request->$method($key); | ||
$expected = current($expected); | ||
} | ||
|
||
$this->assertSame($expected, $actual); | ||
} | ||
|
||
/** @dataProvider methodProvider */ | ||
public function testMethodReturnsSameInstanceWhenSettingValue(string $method, string $property): void | ||
{ | ||
$propertyValue = $this->getPropertyValue($property); | ||
|
||
$value = is_array($propertyValue) | ||
? [$this->faker->word] | ||
: $this->faker->word; | ||
|
||
try { | ||
$actual = $this->request->$method($value); | ||
} catch (TypeError $e) { | ||
$actual = $this->request->$method($this->faker->word, $this->faker->word); | ||
} | ||
|
||
$this->assertInstanceOf(Request::class, $actual); | ||
$this->assertSame($this->request, $actual); | ||
} | ||
|
||
/** @dataProvider encodableProvider */ | ||
public function testMethodsReturnEncodableContentCorrectly(string $property, string $method, string $verifier): void | ||
{ | ||
$content = $this->randomArray(); | ||
|
||
$this->setPropertyValue($property, $content); | ||
|
||
$expected = $content; | ||
$actual = $this->request->$method(true); | ||
|
||
$this->$verifier($expected, $actual); | ||
} | ||
|
||
public function encodableProvider(): array | ||
{ | ||
return [ | ||
['headers', 'headers', 'assertHeadersEncodedCorrectly'], | ||
['parameters', 'parameters', 'assertParametersEncodedCorrectly'], | ||
['queryParameters', 'queryParameters', 'assertQueryParametersEncodedCorrectly'], | ||
]; | ||
} | ||
|
||
public function methodProvider(): array | ||
{ | ||
# [method, property] | ||
|
||
return [ | ||
['url', 'url'], | ||
['path', 'path'], | ||
['method', 'method'], | ||
['header', 'headers'], | ||
['headers', 'headers'], | ||
['parameter', 'parameters'], | ||
['parameters', 'parameters'], | ||
['queryParameter', 'queryParameters'], | ||
['queryParameters', 'queryParameters'], | ||
]; | ||
} | ||
|
||
protected function assertHeadersEncodedCorrectly(array $expected, array $actual): void | ||
{ | ||
$expected = array_map(fn ($key, $value) => "$key: $value", array_keys($expected), array_values($expected)); | ||
|
||
$this->assertEquals($expected, $actual); | ||
$this->assertIsArray($actual); | ||
} | ||
|
||
protected function assertParametersEncodedCorrectly(array $expected, string $actual): void | ||
{ | ||
$expected = json_encode($expected); | ||
|
||
$this->assertSame($expected, $actual); | ||
$this->assertIsString($actual); | ||
} | ||
|
||
protected function assertQueryParametersEncodedCorrectly(array $expected, string $actual): void | ||
{ | ||
$expected = http_build_query($expected); | ||
|
||
$this->assertSame($expected, $actual); | ||
$this->assertIsString($actual); | ||
} | ||
|
||
protected function randomArray(int $count = null): array | ||
{ | ||
$count = $count ?: $this->faker->numberBetween(1, 100); | ||
|
||
$keys = []; | ||
$values = []; | ||
|
||
for ($i = 0; $i < $count; $i++) { | ||
$keys[] = $this->faker->word; | ||
$values[] = $this->faker->word; | ||
} | ||
|
||
return array_combine( | ||
$keys, | ||
$values | ||
); | ||
} | ||
|
||
protected function property(string $name): ReflectionProperty | ||
{ | ||
$reflection = new ReflectionClass($this->request); | ||
$property = $reflection->getProperty($name); | ||
$property->setAccessible(true); | ||
|
||
return $property; | ||
} | ||
|
||
protected function getPropertyValue(string $propertyName) | ||
{ | ||
return $this->property($propertyName)->getValue($this->request); | ||
} | ||
|
||
protected function setPropertyValue(string $propertyName, $value): void | ||
{ | ||
$this->property($propertyName)->setValue($this->request, $value); | ||
} | ||
} |