Skip to content

Commit 1ecacf8

Browse files
authored
Merge pull request #392 from ergebnis/feature/version
Enhancement: Extract `Version`
2 parents cb0531b + ec2ad80 commit 1ecacf8

File tree

9 files changed

+969
-5
lines changed

9 files changed

+969
-5
lines changed

src/Extension.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
use PHPUnit\TextUI;
1818
use PHPUnit\Util;
1919

20-
if (1 !== \preg_match('/(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/', Runner\Version::id(), $matches)) {
20+
try {
21+
$phpUnitVersion = Version\Version::fromString(Runner\Version::id());
22+
} catch (\InvalidArgumentException $exception) {
2123
throw new \RuntimeException(\sprintf(
2224
'Unable to determine PHPUnit version from version identifier "%s".',
2325
Runner\Version::id(),
2426
));
2527
}
2628

27-
$major = (int) $matches['major'];
28-
29-
if (9 === $major) {
29+
if ($phpUnitVersion->major()->equals(Version\Major::fromInt(9))) {
3030
/**
3131
* @internal
3232
*/
@@ -166,7 +166,7 @@ private function resolveMaximumDuration(string $test): Duration
166166
return $this->maximumDuration;
167167
}
168168
}
169-
} elseif (10 <= $major) {
169+
} elseif ($phpUnitVersion->major()->equals(Version\Major::fromInt(10))) {
170170
/**
171171
* @internal
172172
*/

src/Version/Major.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2021-2023 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpunit-slow-test-detector
12+
*/
13+
14+
namespace Ergebnis\PHPUnit\SlowTestDetector\Version;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class Major
20+
{
21+
private int $value;
22+
23+
private function __construct(int $value)
24+
{
25+
$this->value = $value;
26+
}
27+
28+
/**
29+
* @throws \InvalidArgumentException
30+
*/
31+
public static function fromInt(int $value): self
32+
{
33+
if (0 > $value) {
34+
throw new \InvalidArgumentException(\sprintf(
35+
'Value "%d" does not appear to be a valid value for a major version.',
36+
$value,
37+
));
38+
}
39+
40+
return new self($value);
41+
}
42+
43+
public function toInt(): int
44+
{
45+
return $this->value;
46+
}
47+
48+
public function equals(self $other): bool
49+
{
50+
return $this->value === $other->value;
51+
}
52+
}

src/Version/Minor.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2021-2023 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpunit-slow-test-detector
12+
*/
13+
14+
namespace Ergebnis\PHPUnit\SlowTestDetector\Version;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class Minor
20+
{
21+
private int $value;
22+
23+
private function __construct(int $value)
24+
{
25+
$this->value = $value;
26+
}
27+
28+
/**
29+
* @throws \InvalidArgumentException
30+
*/
31+
public static function fromInt(int $value): self
32+
{
33+
if (0 > $value) {
34+
throw new \InvalidArgumentException(\sprintf(
35+
'Value "%d" does not appear to be a valid value for a minor version.',
36+
$value,
37+
));
38+
}
39+
40+
return new self($value);
41+
}
42+
43+
public function toInt(): int
44+
{
45+
return $this->value;
46+
}
47+
}

src/Version/Patch.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2021-2023 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpunit-slow-test-detector
12+
*/
13+
14+
namespace Ergebnis\PHPUnit\SlowTestDetector\Version;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class Patch
20+
{
21+
private int $value;
22+
23+
private function __construct(int $value)
24+
{
25+
$this->value = $value;
26+
}
27+
28+
/**
29+
* @throws \InvalidArgumentException
30+
*/
31+
public static function fromInt(int $value): self
32+
{
33+
if (0 > $value) {
34+
throw new \InvalidArgumentException(\sprintf(
35+
'Value "%d" does not appear to be a valid value for a patch version.',
36+
$value,
37+
));
38+
}
39+
40+
return new self($value);
41+
}
42+
43+
public function toInt(): int
44+
{
45+
return $this->value;
46+
}
47+
}

src/Version/Version.php

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2021-2023 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpunit-slow-test-detector
12+
*/
13+
14+
namespace Ergebnis\PHPUnit\SlowTestDetector\Version;
15+
16+
/**
17+
* @internal
18+
*/
19+
final class Version
20+
{
21+
private Major $major;
22+
private ?Minor $minor;
23+
private ?Patch $patch;
24+
25+
private function __construct(
26+
Major $major,
27+
?Minor $minor,
28+
?Patch $patch
29+
) {
30+
$this->major = $major;
31+
$this->minor = $minor;
32+
$this->patch = $patch;
33+
}
34+
35+
/**
36+
* @throws \InvalidArgumentException
37+
*/
38+
public static function create(
39+
Major $major,
40+
?Minor $minor = null,
41+
?Patch $patch = null
42+
): self {
43+
if (
44+
$patch instanceof Patch
45+
&& !$minor instanceof Minor
46+
) {
47+
throw new \InvalidArgumentException('Patch version requires minor version.');
48+
}
49+
50+
return new self(
51+
$major,
52+
$minor,
53+
$patch,
54+
);
55+
}
56+
57+
/**
58+
* @throws \InvalidArgumentException
59+
*/
60+
public static function fromString(string $value): self
61+
{
62+
if (0 === \preg_match('/^(?P<major>(0|[1-9]\d*))(\.(?P<minor>(0|[1-9]\d*))(\.(?P<patch>(0|[1-9]\d*)))?)?$/', $value, $matches)) {
63+
throw new \InvalidArgumentException(\sprintf(
64+
'Value "%s" does not appear to be a valid value for a semantic version.',
65+
$value,
66+
));
67+
}
68+
69+
$major = Major::fromInt((int) $matches['major']);
70+
$minor = null;
71+
$patch = null;
72+
73+
if (\array_key_exists('minor', $matches)) {
74+
$minor = Minor::fromInt((int) $matches['minor']);
75+
}
76+
77+
if (\array_key_exists('patch', $matches)) {
78+
$patch = Patch::fromInt((int) $matches['patch']);
79+
}
80+
81+
return self::create(
82+
$major,
83+
$minor,
84+
$patch,
85+
);
86+
}
87+
88+
public function major(): Major
89+
{
90+
return $this->major;
91+
}
92+
93+
public function minor(): ?Minor
94+
{
95+
return $this->minor;
96+
}
97+
98+
public function patch(): ?Patch
99+
{
100+
return $this->patch;
101+
}
102+
103+
public function toString(): string
104+
{
105+
if (!$this->minor instanceof Minor) {
106+
return (string) $this->major->toInt();
107+
}
108+
109+
if (!$this->patch instanceof Patch) {
110+
return \sprintf(
111+
'%d.%d',
112+
$this->major->toInt(),
113+
$this->minor->toInt(),
114+
);
115+
}
116+
117+
return \sprintf(
118+
'%d.%d.%d',
119+
$this->major->toInt(),
120+
$this->minor->toInt(),
121+
$this->patch->toInt(),
122+
);
123+
}
124+
125+
public function compare(self $other): int
126+
{
127+
$normalizedThis = self::normalize($this);
128+
$normalizedOther = self::normalize($other);
129+
130+
if ($normalizedThis->major->toInt() < $normalizedOther->major->toInt()) {
131+
return -1;
132+
}
133+
134+
if ($normalizedThis->major->toInt() > $normalizedOther->major->toInt()) {
135+
return 1;
136+
}
137+
138+
\assert($normalizedThis->minor instanceof Minor);
139+
\assert($normalizedOther->minor instanceof Minor);
140+
141+
if ($normalizedThis->minor->toInt() < $normalizedOther->minor->toInt()) {
142+
return -1;
143+
}
144+
145+
if ($normalizedThis->minor->toInt() > $normalizedOther->minor->toInt()) {
146+
return 1;
147+
}
148+
149+
\assert($normalizedThis->patch instanceof Patch);
150+
\assert($normalizedOther->patch instanceof Patch);
151+
152+
if ($normalizedThis->patch->toInt() < $normalizedOther->patch->toInt()) {
153+
return -1;
154+
}
155+
156+
if ($normalizedThis->patch->toInt() > $normalizedOther->patch->toInt()) {
157+
return 1;
158+
}
159+
160+
return 0;
161+
}
162+
163+
private static function normalize(self $version): self
164+
{
165+
if (!$version->minor instanceof Minor) {
166+
return new self(
167+
$version->major,
168+
Minor::fromInt(0),
169+
Patch::fromInt(0),
170+
);
171+
}
172+
173+
if (!$version->patch instanceof Patch) {
174+
return new self(
175+
$version->major,
176+
$version->minor,
177+
Patch::fromInt(0),
178+
);
179+
}
180+
181+
return $version;
182+
}
183+
}

0 commit comments

Comments
 (0)