Skip to content

Commit

Permalink
Enhancement: Implement Version
Browse files Browse the repository at this point in the history
  • Loading branch information
localheinz committed Dec 24, 2023
1 parent 3bff003 commit 0dabcac
Show file tree
Hide file tree
Showing 10 changed files with 309 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
dependencies: "${{ matrix.dependencies }}"

- name: "Run backward-compatibility analysis with roave/backward-compatibility-check"
run: "vendor/bin/roave-backward-compatibility-check --ansi --format=github-actions --from=64ced12"
run: "vendor/bin/roave-backward-compatibility-check --ansi --format=github-actions --from=6e3389d"

code-coverage:
name: "Code Coverage"
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

For a full diff see [`64ced12...main`][64ced12...main].

### Added

- Added `Version` as a value object ([#1]), by [@localheinz]

[64ced12...main]: https://github.com/ergebnis/version/compare/64ced12...main

[#1]: https://github.com/ergebnis/version/pull/1

[@localheinz]: https://github.com/localheinz
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ it: refactoring coding-standards security-analysis static-code-analysis tests ##

.PHONY: backward-compatibility-analysis
backward-compatibility-analysis: vendor ## Runs a backward-compatibility analysis with roave/backward-compatibility-check
vendor/bin/roave-backward-compatibility-check --from=64ced12
vendor/bin/roave-backward-compatibility-check --from=6e3389d

.PHONY: code-coverage
code-coverage: vendor ## Collects coverage from running unit tests with phpunit/phpunit
Expand Down
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,34 @@ composer require ergebnis/version

## Usage

💡 This is a great place for showing a few usage examples!
### Create a `Version` from a `string`

```php
<?php

declare(strict_types=1);

use Ergebnis\Version;

$version = Version\Version::fromString('1.2.3');
```

### Compare a `Version` to another `Version`

```php
<?php

declare(strict_types=1);

use Ergebnis\Version;

$one = Version\Version::fromString('1.2.3');
$two = Version\Version::fromString('1.2.3');
$three = Version\Version::fromString('1.2.4');

$one->equals($two); // true
$one->equals($three); // false
```

## Changelog

Expand Down
9 changes: 8 additions & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.18.0@b113f3ed0259fd6e212d87c3df80eec95a6abf19"/>
<files psalm-version="5.18.0@b113f3ed0259fd6e212d87c3df80eec95a6abf19">
<file src="test/Unit/VersionTest.php">
<PossiblyUnusedMethod>
<code>provideInvalidValue</code>
<code>provideValidValue</code>
</PossiblyUnusedMethod>
</file>
</files>
18 changes: 6 additions & 12 deletions src/Example.php → src/Exception/InvalidVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
* @see https://github.com/ergebnis/version
*/

namespace Ergebnis\Version;
namespace Ergebnis\Version\Exception;

final class Example
final class InvalidVersion extends \InvalidArgumentException
{
private function __construct(private readonly string $value)
{
}

public static function fromString(string $value): self
{
return new self($value);
}

public function toString(): string
{
return $this->value;
return new self(\sprintf(
'Value "%s" does not appear to be valid.',
$value,
));
}
}
49 changes: 49 additions & 0 deletions src/Version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/version
*/

namespace Ergebnis\Version;

final class Version
{
/**
* @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
* @see https://regex101.com/r/Ly7O1x/3/
*/
private const REGEX = '/^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/';

private function __construct(private readonly string $value)
{
}

/**
* @throws Exception\InvalidVersion
*/
public static function fromString(string $value): self
{
if (1 !== \preg_match(self::REGEX, $value)) {
throw Exception\InvalidVersion::fromString($value);

Check warning on line 34 in src/Version.php

View check run for this annotation

Codecov / codecov/patch

src/Version.php#L34

Added line #L34 was not covered by tests
}

return new self($value);
}

public function toString(): string
{
return $this->value;
}

public function equals(self $other): bool
{
return $this->value === $other->value;
}
}
33 changes: 0 additions & 33 deletions test/Unit/ExampleTest.php

This file was deleted.

38 changes: 38 additions & 0 deletions test/Unit/Exception/InvalidVersionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/version
*/

namespace Ergebnis\Version\Test\Unit\Exception;

use Ergebnis\Version\Exception;
use Ergebnis\Version\Test;
use PHPUnit\Framework;

#[Framework\Attributes\CoversClass(Exception\InvalidVersion::class)]
final class InvalidVersionTest extends Framework\TestCase
{
use Test\Util\Helper;

public function testFromStringReturnsException(): void
{
$value = self::faker()->word();

$exception = Exception\InvalidVersion::fromString($value);

$message = \sprintf(
'Value "%s" does not appear to be valid.',
$value,
);

self::assertSame($message, $exception->getMessage());
}
}
170 changes: 170 additions & 0 deletions test/Unit/VersionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/version
*/

namespace Ergebnis\Version\Test\Unit;

use Ergebnis\DataProvider;
use Ergebnis\Version\Exception;
use Ergebnis\Version\Test;
use Ergebnis\Version\Version;
use PHPUnit\Framework;

#[Framework\Attributes\CoversClass(Version::class)]
final class VersionTest extends Framework\TestCase
{
use Test\Util\Helper;

#[Framework\Attributes\DataProviderExternal(DataProvider\StringProvider::class, 'blank')]
#[Framework\Attributes\DataProviderExternal(DataProvider\StringProvider::class, 'empty')]
public function testFromStringRejectsInvalidValue(string $value): void
{
$this->expectException(Exception\InvalidVersion::class);

Version::fromString($value);
}

/**
* @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
* @see https://regex101.com/r/Ly7O1x/3/
*
* @return \Generator<string, array{0: string}>
*/
public static function provideInvalidValue(): \Generator
{
$values = [
'1',
'1.2',
'1.2.3-0123',
'1.2.3-0123.0123',
'1.1.2+.123',
'+invalid',
'-invalid',
'-invalid+invalid',
'-invalid.01',
'alpha',
'alpha.beta',
'alpha.beta.1',
'alpha.1',
'alpha+beta',
'alpha_beta',
'alpha.',
'alpha..',
'beta',
'1.0.0-alpha_beta',
'-alpha.',
'1.0.0-alpha..',
'1.0.0-alpha..1',
'1.0.0-alpha...1',
'1.0.0-alpha....1',
'1.0.0-alpha.....1',
'1.0.0-alpha......1',
'1.0.0-alpha.......1',
'01.1.1',
'1.01.1',
'1.1.01',
'1.2',
'1.2.3.DEV',
'1.2-SNAPSHOT',
'1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788',
'1.2-RC-SNAPSHOT',
'-1.0.3-gamma+b7718',
'+justmeta',
'9.8.7+meta+meta',
'9.8.7-whatever+meta+meta',
'99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12',
];

foreach ($values as $value) {
yield $value => [
$value,
];
}
}

#[Framework\Attributes\DataProvider('provideValidValue')]
public function testFromStringReturnsVersion(string $value): void
{
$version = Version::fromString($value);

self::assertSame($value, $version->toString());
}

/**
* @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
* @see https://regex101.com/r/Ly7O1x/3/
*
* @return \Generator<string, array{0: string}>
*/
public static function provideValidValue(): \Generator
{
$values = [
'0.0.4',
'1.2.3',
'10.20.30',
'1.1.2-prerelease+meta',
'1.1.2+meta',
'1.1.2+meta-valid',
'1.0.0-alpha',
'1.0.0-beta',
'1.0.0-alpha.beta',
'1.0.0-alpha.beta.1',
'1.0.0-alpha.1',
'1.0.0-alpha0.valid',
'1.0.0-alpha.0valid',
'1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay',
'1.0.0-rc.1+build.1',
'2.0.0-rc.1+build.123',
'1.2.3-beta',
'10.2.3-DEV-SNAPSHOT',
'1.2.3-SNAPSHOT-123',
'1.0.0',
'2.0.0',
'1.1.7',
'2.0.0+build.1848',
'2.0.1-alpha.1227',
'1.0.0-alpha+beta',
'1.2.3----RC-SNAPSHOT.12.9.1--.12+788',
'1.2.3----R-S.12.9.1--.12+meta',
'1.2.3----RC-SNAPSHOT.12.9.1--.12',
'1.0.0+0.build.1-rc.10000aaa-kk-0.1',
'99999999999999999999999.999999999999999999.99999999999999999',
'1.0.0-0A.is.legal',
];

foreach ($values as $value) {
yield $value => [
$value,
];
}
}

public function testEqualsReturnsFalseWhenValuesAreDifferent(): void
{
$faker = self::faker()->unique();

$one = Version::fromString($faker->regexify('(0|[1-9]+)\.(0|[1-9]+)\.(0|[1-9]+)'));
$two = Version::fromString($faker->regexify('(0|[1-9]+)\.(0|[1-9]+)\.(0|[1-9]+)'));

self::assertFalse($one->equals($two));
}

public function testEqualsReturnsTrueWhenValueIsSame(): void
{
$value = self::faker()->regexify('(0|[1-9]+)\.(0|[1-9]+)\.(0|[1-9]+)');

$one = Version::fromString($value);
$two = Version::fromString($value);

self::assertTrue($one->equals($two));
}
}

0 comments on commit 0dabcac

Please sign in to comment.