Skip to content

Commit 8b70551

Browse files
committed
Refactor tests
1 parent fb6e464 commit 8b70551

19 files changed

+380
-286
lines changed

.github/workflows/quality-assurance.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ jobs:
1010
runs-on: ubuntu-latest
1111
strategy:
1212
matrix:
13-
php: [ '7.4' ]
13+
php: [ '7.4', '8.0' ]
1414
composer-flags: [ '' ]
1515
phpunit-flags: [ '--coverage-text' ]
16-
include:
17-
- php: '8.0'
18-
composer-flags: '--ignore-platform-req=php'
19-
phpunit-flags: '--no-coverage'
2016
steps:
2117
- uses: actions/checkout@v2
2218
- uses: shivammathur/setup-php@v2

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ PHP Domain Parser is compliant around:
2929
### Composer
3030

3131
~~~
32-
$ composer require jeremykendall/php-domain-parser:^6.0
32+
$ composer require jeremykendall/php-domain-parser
3333
~~~
3434

3535
### System Requirements

src/Domain.php

Lines changed: 45 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,20 @@
2929

3030
final class Domain implements DomainName
3131
{
32-
private const REGEXP_IDN_PATTERN = '/[^\x20-\x7f]/';
3332
private const IDNA_2003 = 'IDNA_2003';
3433
private const IDNA_2008 = 'IDNA_2008';
34+
private const REGEXP_IDN_PATTERN = '/[^\x20-\x7f]/';
35+
36+
// Note that unreserved is purposely missing . as it is used to separate labels.
37+
private const REGEXP_REGISTERED_NAME = '/(?(DEFINE)
38+
(?<unreserved>[a-z0-9_~\-])
39+
(?<sub_delims>[!$&\'()*+,;=])
40+
(?<encoded>%[A-F0-9]{2})
41+
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded)){1,63})
42+
)
43+
^(?:(?&reg_name)\.){0,126}(?&reg_name)\.?$/ix';
44+
45+
private const REGEXP_URI_DELIMITERS = '/[:\/?#\[\]@ ]/';
3546

3647
/**
3748
* @var array<string>
@@ -45,56 +56,51 @@ final class Domain implements DomainName
4556
/**
4657
* @param null|mixed $domain
4758
*/
48-
private function __construct($domain, string $type)
59+
private function __construct(string $type, $domain)
4960
{
5061
$this->type = $type;
51-
[$this->domain, $this->labels] = $this->parseDomain($domain);
62+
$this->domain = $this->parseDomain($domain);
63+
$this->labels = null === $this->domain ? [] : array_reverse(explode('.', $this->domain));
5264
}
5365

5466
/**
5567
* @param array{domain:string|null, type:string} $properties
5668
*/
5769
public static function __set_state(array $properties): self
5870
{
59-
return new self($properties['domain'], $properties['type']);
71+
return new self($properties['type'], $properties['domain']);
6072
}
6173

6274
/**
6375
* @param null|mixed $domain
6476
*/
6577
public static function fromIDNA2003($domain): self
6678
{
67-
return new self($domain, self::IDNA_2003);
79+
return new self(self::IDNA_2003, $domain);
6880
}
6981

7082
/**
7183
* @param null|mixed $domain
7284
*/
7385
public static function fromIDNA2008($domain): self
7486
{
75-
return new self($domain, self::IDNA_2008);
87+
return new self(self::IDNA_2008, $domain);
7688
}
7789

7890
/**
7991
* @param mixed $domain a domain
80-
*
81-
* @return array{0:string|null, 1:array<string>}
8292
*/
83-
private function parseDomain($domain): array
93+
private function parseDomain($domain): ?string
8494
{
8595
if ($domain instanceof DomainNameProvider) {
8696
$domain = $domain->domain();
8797
}
8898

89-
if (!$domain instanceof DomainName) {
90-
if ($domain instanceof Host) {
91-
$domain = $domain->toUnicode()->value();
92-
}
93-
94-
return $this->parseValue($domain);
99+
if ($domain instanceof Host) {
100+
return $this->parseValue($domain->toUnicode()->value());
95101
}
96102

97-
return $this->parseValue($domain->toUnicode()->value());
103+
return $this->parseValue($domain);
98104
}
99105

100106
/**
@@ -108,13 +114,11 @@ private function parseDomain($domain): array
108114
*
109115
* @throws SyntaxError If the host is not a domain
110116
* @throws SyntaxError If the domain is not a host
111-
*
112-
* @return array{0:string|null, 1:array<string>}
113117
*/
114-
private function parseValue($domain): array
118+
private function parseValue($domain): ?string
115119
{
116120
if (null === $domain) {
117-
return [null, []];
121+
return null;
118122
}
119123

120124
if (is_object($domain) && method_exists($domain, '__toString')) {
@@ -127,7 +131,7 @@ private function parseValue($domain): array
127131

128132
$domain = (string) $domain;
129133
if ('' === $domain) {
130-
return ['', ['']];
134+
return '';
131135
}
132136

133137
$res = filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
@@ -136,24 +140,12 @@ private function parseValue($domain): array
136140
}
137141

138142
$formattedDomain = rawurldecode($domain);
139-
140-
// Note that unreserved is purposely missing . as it is used to separate labels.
141-
static $domainName = '/(?(DEFINE)
142-
(?<unreserved>[a-z0-9_~\-])
143-
(?<sub_delims>[!$&\'()*+,;=])
144-
(?<encoded>%[A-F0-9]{2})
145-
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded)){1,63})
146-
)
147-
^(?:(?&reg_name)\.){0,126}(?&reg_name)\.?$/ix';
148-
if (1 === preg_match($domainName, $formattedDomain)) {
149-
$formattedDomain = strtolower($formattedDomain);
150-
151-
return [$formattedDomain, array_reverse(explode('.', $formattedDomain))];
143+
if (1 === preg_match(self::REGEXP_REGISTERED_NAME, $formattedDomain)) {
144+
return strtolower($formattedDomain);
152145
}
153146

154147
// a domain name can not contains URI delimiters or space
155-
static $genDelimiters = '/[:\/?#\[\]@ ]/';
156-
if (1 === preg_match($genDelimiters, $formattedDomain)) {
148+
if (1 === preg_match(self::REGEXP_URI_DELIMITERS, $formattedDomain)) {
157149
throw SyntaxError::dueToInvalidCharacters($domain);
158150
}
159151

@@ -162,11 +154,7 @@ private function parseValue($domain): array
162154
throw SyntaxError::dueToInvalidLength($domain);
163155
}
164156

165-
$formattedDomain = $this->domainToUnicode($this->domainToAscii($formattedDomain));
166-
167-
$labels = array_reverse(explode('.', $formattedDomain));
168-
169-
return [$formattedDomain, $labels];
157+
return $this->domainToUnicode($this->domainToAscii($formattedDomain));
170158
}
171159

172160
private function domainToAscii(string $domain): string
@@ -206,7 +194,7 @@ public function isAscii(): bool
206194

207195
public function jsonSerialize(): ?string
208196
{
209-
return $this->value();
197+
return $this->domain;
210198
}
211199

212200
public function count(): int
@@ -221,7 +209,7 @@ public function value(): ?string
221209

222210
public function toString(): string
223211
{
224-
return (string) $this->value();
212+
return (string) $this->domain;
225213
}
226214

227215
public function label(int $key): ?string
@@ -264,7 +252,7 @@ public function toAscii(): self
264252
return $this;
265253
}
266254

267-
return new self($domain, $this->type);
255+
return new self($this->type, $domain);
268256
}
269257

270258
public function toUnicode(): self
@@ -278,7 +266,7 @@ public function toUnicode(): self
278266
return $this;
279267
}
280268

281-
return new self($domain, $this->type);
269+
return new self($this->type, $domain);
282270
}
283271

284272
/**
@@ -330,13 +318,13 @@ public function append($label): self
330318

331319
public function withLabel(int $key, $label): self
332320
{
333-
$nb_labels = count($this->labels);
334-
if ($key < - $nb_labels - 1 || $key > $nb_labels) {
321+
$nbLabels = count($this->labels);
322+
if ($key < - $nbLabels - 1 || $key > $nbLabels) {
335323
throw SyntaxError::dueToInvalidLabelKey($this, $key);
336324
}
337325

338326
if (0 > $key) {
339-
$key = $nb_labels + $key;
327+
$key = $nbLabels + $key;
340328
}
341329

342330
$label = $this->normalize($label);
@@ -349,28 +337,28 @@ public function withLabel(int $key, $label): self
349337
$labels[$key] = $label;
350338
ksort($labels);
351339

352-
return new self(implode('.', array_reverse($labels)), $this->type);
340+
return new self($this->type, implode('.', array_reverse($labels)));
353341
}
354342

355343
public function withoutLabel(int $key, int ...$keys): self
356344
{
357345
array_unshift($keys, $key);
358-
$nb_labels = count($this->labels);
346+
$nbLabels = count($this->labels);
359347
foreach ($keys as &$offset) {
360-
if (- $nb_labels > $offset || $nb_labels - 1 < $offset) {
348+
if (- $nbLabels > $offset || $nbLabels - 1 < $offset) {
361349
throw SyntaxError::dueToInvalidLabelKey($this, $key);
362350
}
363351

364352
if (0 > $offset) {
365-
$offset += $nb_labels;
353+
$offset += $nbLabels;
366354
}
367355
}
368356
unset($offset);
369357

370-
$deleted_keys = array_keys(array_count_values($keys));
358+
$deletedKeys = array_keys(array_count_values($keys));
371359
$labels = [];
372360
foreach ($this->labels as $offset => $label) {
373-
if (!in_array($offset, $deleted_keys, true)) {
361+
if (!in_array($offset, $deletedKeys, true)) {
374362
$labels[] = $label;
375363
}
376364
}
@@ -388,13 +376,13 @@ public function clear(): self
388376
return $this;
389377
}
390378

391-
return new self(null, $this->type);
379+
return new self($this->type, null);
392380
}
393381

394382
public function slice(int $offset, int $length = null): self
395383
{
396-
$nb_labels = count($this->labels);
397-
if ($offset < - $nb_labels || $offset > $nb_labels) {
384+
$nbLabels = count($this->labels);
385+
if ($offset < - $nbLabels || $offset > $nbLabels) {
398386
throw SyntaxError::dueToInvalidLabelKey($this, $offset);
399387
}
400388

src/DomainTest.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class DomainTest extends TestCase
1818
*/
1919
public function testToAsciiThrowsException(string $domain): void
2020
{
21-
self::expectException(SyntaxError::class);
21+
$this->expectException(SyntaxError::class);
2222

2323
Domain::fromIDNA2008($domain);
2424
}
@@ -37,7 +37,7 @@ public function invalidDomainProvider(): iterable
3737

3838
public function testToUnicodeThrowsException(): void
3939
{
40-
self::expectException(SyntaxError::class);
40+
$this->expectException(SyntaxError::class);
4141

4242
Domain::fromIDNA2008('xn--a-ecp.ru')->toUnicode();
4343
}
@@ -95,6 +95,7 @@ public function testOffsets(): void
9595

9696
self::assertSame([0, 2], $domain->keys('com'));
9797
self::assertSame([], $domain->keys('toto'));
98+
self::assertSame([0, 1, 2, 3], $domain->keys());
9899
}
99100

100101
public function testLabels(): void
@@ -310,19 +311,19 @@ public function withLabelWorksProvider(): iterable
310311

311312
public function testWithLabelFailsWithTypeError(): void
312313
{
313-
self::expectException(TypeError::class);
314+
$this->expectException(TypeError::class);
314315
Domain::fromIDNA2008('example.com')->withLabel(1, new \stdClass());
315316
}
316317

317318
public function testWithLabelFailsWithInvalidKey(): void
318319
{
319-
self::expectException(SyntaxError::class);
320+
$this->expectException(SyntaxError::class);
320321
Domain::fromIDNA2008('example.com')->withLabel(-4, 'www');
321322
}
322323

323324
public function testWithLabelFailsWithInvalidLabel2(): void
324325
{
325-
self::expectException(SyntaxError::class);
326+
$this->expectException(SyntaxError::class);
326327

327328
Domain::fromIDNA2008('example.com')->withLabel(-1, '');
328329
}
@@ -411,7 +412,7 @@ public function withoutLabelWorksProvider(): iterable
411412

412413
public function testwithoutLabelFailsWithInvalidKey(): void
413414
{
414-
self::expectException(SyntaxError::class);
415+
$this->expectException(SyntaxError::class);
415416
Domain::fromIDNA2008('example.com')->withoutLabel(-3);
416417
}
417418

@@ -502,7 +503,7 @@ public function testSlice(): void
502503

503504
public function testSliceThrowsOnOverFlow(): void
504505
{
505-
self::expectException(SyntaxError::class);
506+
$this->expectException(SyntaxError::class);
506507

507508
Domain::fromIDNA2008('ulb.ac.be')->slice(5);
508509
}

0 commit comments

Comments
 (0)