Skip to content

Commit d9c9f2c

Browse files
committed
Add missing tests for DisplayString type
1 parent f310ec5 commit d9c9f2c

12 files changed

+99
-61
lines changed

.php-cs-fixer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
'import_constants' => true,
1818
'import_functions' => true,
1919
],
20-
'new_with_braces' => true,
20+
'new_with_parentheses' => true,
2121
'no_blank_lines_after_phpdoc' => true,
2222
'no_empty_phpdoc' => true,
2323
'no_empty_comment' => true,

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
99
- Support for the `DisplayString` type
1010
- `ByteSequence::tryFromEncoded`
1111
- `Token::tryFromString`
12-
- Adding functional API via `Bakame\Http\StructuredFields\parse` and `Bakame\Http\StructuredFields\build`
12+
- Adding functional API via `http_parse_sf` and `http_build_sf`
1313

1414
### Fixed
1515

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,26 @@ use Bakame\Http\StructuredFields\Token;
1919

2020
//1 - parsing an Accept Header
2121
$headerValue = 'text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8';
22-
$field = parse($headerValue, 'list');
22+
$field = http_parse_structured_field('list', $headerValue);
2323
$field[2]->value()->toString(); // returns 'application/xml'
2424
$field[2]->parameter('q'); // returns (float) 0.9
2525
$field[0]->value()->toString(); // returns 'text/html'
2626
$field[0]->parameter('q'); // returns null
2727

2828
//2 - building a Retrofit Cookie Header
29-
echo build(OuterList::new(
30-
InnerList::fromAssociative(['foo', 'bar'], [
29+
echo http_build_structured_field('list', [
30+
[
31+
['foo', 'bar'],
32+
[
3133
'expire' => $expire,
3234
'path' => '/',
3335
'max-age' => 2500,
3436
'secure' => true,
3537
'httponly' => true,
3638
'samesite' => Token::fromString('lax'),
37-
])
38-
));
39+
]
40+
]
41+
]);
3942
// returns ("foo" "bar");expire=@1681504328;path="/";max-age=2500;secure;httponly=?0;samesite=lax
4043
```
4144

@@ -88,10 +91,10 @@ compliant HTTP field string value. To ease integration, the `__toString` method
8891
implemented as an alias to the `toHttpValue` method.
8992

9093
````php
91-
use function Bakame\Http\StructuredFields\parse;
92-
use function Bakame\Http\StructuredFields\build;
94+
use function Bakame\Http\StructuredFields\http_sf_parse;
95+
use function Bakame\Http\StructuredFields\http_sf_build;
9396

94-
$field = parse('bar; baz=42; secure=?1', 'item');
97+
$field = http_sf_parse('bar; baz=42; secure=?1', 'item');
9598
echo $field->toHttpValue(); // return 'bar;baz=42;secure'
9699
// on serialization the field has been normalized
97100

@@ -102,7 +105,7 @@ header('foo: '. $field->toHttpValue());
102105
//or
103106
header('foo: '. $field);
104107
//or
105-
header('foo: '. build($field));
108+
header('foo: '. http_sf_build($field));
106109
````
107110

108111
All five (5) structured data type as defined in the RFC are provided inside the

src/DataType.php

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/DisplayString.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Bakame\Http\StructuredFields;
66

77
use Stringable;
8-
98
use Throwable;
109

1110
use function preg_match;
@@ -14,7 +13,7 @@
1413
use function rawurlencode;
1514

1615
/**
17-
* @see https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3.5
16+
* @see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-sfbis#section-4.2.10
1817
*/
1918
final class DisplayString
2019
{

src/Item.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,26 @@ public static function fromDecodedByteSequence(Stringable|string $value): self
120120
return self::fromValue(Value::fromDecodedByteSequence($value));
121121
}
122122

123+
/**
124+
* Returns a new instance from an encoded byte sequence and an iterable of key-value parameters.
125+
*
126+
* @throws SyntaxError if the sequence is invalid
127+
*/
128+
public static function fromEncodedDisplayString(Stringable|string $value): self
129+
{
130+
return self::fromValue(Value::fromEncodedDisplayString($value));
131+
}
132+
133+
/**
134+
* Returns a new instance from a decoded byte sequence and an iterable of key-value parameters.
135+
*
136+
* @throws SyntaxError if the sequence is invalid
137+
*/
138+
public static function fromDecodedDisplayString(Stringable|string $value): self
139+
{
140+
return self::fromValue(Value::fromDecodedDisplayString($value));
141+
}
142+
123143
/**
124144
* Returns a new instance from a Token and an iterable of key-value parameters.
125145
*

src/Parser.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ private static function extractString(string $httpValue): array
412412
/**
413413
* Returns a string from an HTTP textual representation and the consumed offset in a tuple.
414414
*
415-
* @see https://www.rfc-editor.org/rfc/rfc8941.html#section-4.2.5
415+
* @see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-sfbis#section-4.2.10
416416
*
417417
* @return array{0:DisplayString, 1:int}
418418
*/
@@ -448,11 +448,6 @@ private static function extractDisplayString(string $httpValue): array
448448
throw new SyntaxError("The HTTP textual representation '$httpValue' for a DisplayString contains uppercased percent encoding sequence.");
449449
}
450450

451-
$intOctet = hexdec($octet);
452-
if ($intOctet < 31 && $intOctet > 127) {
453-
throw new SyntaxError("The HTTP textual representation '$httpValue' for a DisplayString contains invalid encoded sequence. $octet - $intOctet");
454-
}
455-
456451
$output .= $char.$octet;
457452
}
458453

src/functions.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,29 @@
22

33
declare(strict_types=1);
44

5-
namespace Bakame\Http\StructuredFields;
5+
use Bakame\Http\StructuredFields\Dictionary;
6+
use Bakame\Http\StructuredFields\InnerList;
7+
use Bakame\Http\StructuredFields\Item;
8+
use Bakame\Http\StructuredFields\OuterList;
9+
use Bakame\Http\StructuredFields\Parameters;
10+
use Bakame\Http\StructuredFields\StructuredField;
611

7-
if (!function_exists('parse')) {
12+
if (!function_exists('http_parse_structured_field')) {
813
/**
914
* Parse a header conform to the HTTP Structured Field RFCs.
1015
*
11-
* @param 'dictionary'|'list'|'item' $type
12-
*
13-
*/
14-
function parse(string $httpValue, string $type): StructuredField
15-
{
16-
return DataType::from($type)->newStructuredField($httpValue);
17-
}
18-
}
19-
20-
if (!function_exists('build')) {
21-
/**
22-
* Build an HTTP header value from a HTTP Structured Field instance.
16+
* @param 'dictionary'|'parameters'|'list'|'innerlist'|'item' $type
17+
* @throws OutOfRangeException If the value is unknown or undefined
2318
*/
24-
function build(StructuredField $structuredField): string
19+
function http_parse_structured_field(string $type, string $httpValue): StructuredField
2520
{
26-
return $structuredField->toHttpValue();
21+
return match ($type) {
22+
'dictionary' => Dictionary::fromHttpValue($httpValue),
23+
'parameters' => Parameters::fromHttpValue($httpValue),
24+
'list' => OuterList::fromHttpValue($httpValue),
25+
'innerlist' => InnerList::fromHttpValue($httpValue),
26+
'item' => Item::fromHttpValue($httpValue), /* @phpstan-ignore-line */
27+
default => throw new ValueError('The submitted type "'.$type.'" is unknown or not supported,'), /* @phpstan-ignore-line */
28+
};
2729
}
2830
}

tests/DisplayStringTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ public function it_will_fail_on_invalid_decoded_string(): void
2929
DisplayString::fromEncoded('%c3%28"');
3030
}
3131

32+
#[Test]
33+
public function it_will_fail_on_invalid_encoded_string_with_utf8_char(): void
34+
{
35+
$this->expectException(SyntaxError::class);
36+
37+
DisplayString::fromEncoded('%c3é"');
38+
}
39+
3240
#[Test]
3341
public function it_will_return_null_on_invalid_encoded_string(): void
3442
{
@@ -37,7 +45,7 @@ public function it_will_return_null_on_invalid_encoded_string(): void
3745
}
3846

3947
#[Test]
40-
public function it_can_decode_base64_field(): void
48+
public function it_can_decode_an_encoded_field(): void
4149
{
4250
$encoded = 'foo %22bar%22 \ baz';
4351
$value = DisplayString::fromEncoded($encoded);

tests/ItemTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ public static function provideInvalidArguments(): iterable
7575

7676
#[Test]
7777
#[DataProvider('provideFrom1stArgument')]
78-
public function it_instantiate_many_types(ByteSequence|Token|DateTimeInterface|string|int|float|bool $value, string $expected): void
78+
public function it_instantiate_many_types(ByteSequence|Token|DisplayString|DateTimeInterface|string|int|float|bool $value, string $expected): void
7979
{
8080
self::assertSame($expected, Item::new($value)->toHttpValue());
8181
}
8282

8383
#[Test]
8484
#[DataProvider('provideFrom1stArgument')]
85-
public function it_updates_item(ByteSequence|Token|DateTimeInterface|string|int|float|bool $value, string $expected): void
85+
public function it_updates_item(ByteSequence|Token|DisplayString|DateTimeInterface|string|int|float|bool $value, string $expected): void
8686
{
8787
$parameters = Parameters::fromAssociative(['foo' => 'bar']);
8888

@@ -100,6 +100,7 @@ public static function provideFrom1stArgument(): iterable
100100
return [
101101
'decimal' => ['value' => 42.0, 'expected' => '42.0'],
102102
'string' => ['value' => 'forty-two', 'expected' => '"forty-two"'],
103+
'detail string' => ['value' => DisplayString::fromDecoded('😊'), 'expected' => '%"%f0%9f%98%8a"'],
103104
'integer' => ['value' => 42, 'expected' => '42'],
104105
'boolean true' => ['value' => true, 'expected' => '?1'],
105106
'boolean false' => ['value' => false, 'expected' => '?0'],
@@ -241,6 +242,16 @@ public function it_instantiates_a_binary(): void
241242
self::assertEquals($byteSequence, Item::fromEncodedByteSequence('Zm9vYmFy')->value());
242243
}
243244

245+
#[Test]
246+
public function it_instantiates_a_display_string(): void
247+
{
248+
$displayString = DisplayString::fromDecoded('😊');
249+
250+
self::assertEquals($displayString, Item::new(DisplayString::fromDecoded('😊'))->value());
251+
self::assertEquals($displayString, Item::fromDecodedDisplayString('😊')->value());
252+
self::assertEquals($displayString, Item::fromEncodedDisplayString('%f0%9f%98%8a')->value());
253+
}
254+
244255
#[Test]
245256
public function it_instantiates_a_string(): void
246257
{
@@ -276,6 +287,10 @@ public static function itemTypeProvider(): iterable
276287
'item' => Item::new('42'),
277288
'expectedType' => Type::ByteSequence,
278289
],
290+
'display string' => [
291+
'item' => Item::new(DisplayString::fromDecoded('😊')),
292+
'expectedType' => Type::DisplayString,
293+
],
279294
'token' => [
280295
'item' => Item::new(Token::fromString('forty-two')),
281296
'expectedType' => Type::Token,
@@ -300,6 +315,7 @@ public function in_can_be_instantiated_using_bare_items(): void
300315
{
301316
$parameters = [
302317
'string' => '42',
318+
'displaystring' => DisplayString::fromDecoded('😊'),
303319
'integer' => 42,
304320
'float' => 4.2,
305321
'boolean' => true,

0 commit comments

Comments
 (0)