mirror of
https://github.com/beste/clock.git
synced 2026-10-17 19:27:35 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0754922206 | ||
|
|
df585ab815 | ||
|
|
c094cf87e3 | ||
|
|
c2243a5934 | ||
|
|
e8f20c112e | ||
|
|
7db7032723 | ||
|
|
8f5274748c | ||
|
|
e73aacc19c | ||
|
|
c062aff727 | ||
|
|
b4408036c1 | ||
|
|
0a55b7a019 | ||
|
|
9818902960 | ||
|
|
622d86328b | ||
|
|
bebff7fd27 | ||
|
|
2c5bf134e4 | ||
|
|
8f0a5a5f6c | ||
|
|
e7b50902b0 | ||
|
|
264e712f65 | ||
|
|
ebe8de302d | ||
|
|
4bd164d047 | ||
|
|
5ae0cc3a8d | ||
|
|
0611b8339d | ||
|
|
729cb30697 | ||
|
|
dc84fbe85a | ||
|
|
93c6f6dca7 | ||
|
|
e4b5b09932 | ||
|
|
9c852bc985 | ||
|
|
48c449b37e | ||
|
|
ff31026046 | ||
|
|
d623da43da | ||
|
|
5a0bf8fdba | ||
|
|
88ddce2cd7 | ||
|
|
26ac2fab9a | ||
|
|
0b23a6d481 | ||
|
|
2e9fb8d220 | ||
|
|
1278a71f80 | ||
|
|
17e1c4ce7e | ||
|
|
0d80994228 | ||
|
|
1a2fab532b | ||
|
|
84e729ce8c | ||
|
|
06686333c0 | ||
|
|
621355dffd | ||
|
|
88afd40a02 | ||
|
|
ec0d9b2006 | ||
|
|
c3758513b5 | ||
|
|
6fcddef411 | ||
|
|
b69661437f | ||
|
|
fc7cb0d32c | ||
|
|
05159b138f | ||
|
|
d29ed0d755 | ||
|
|
52bafeb8e3 | ||
|
|
e9ceb17d59 | ||
|
|
3861182e4f | ||
|
|
6d38f044b3 | ||
|
|
aac77907e3 | ||
|
|
ed1c70ffdf | ||
|
|
8ec664cfae | ||
|
|
5af4eaf534 | ||
|
|
4b68b50507 | ||
|
|
0999d2836d | ||
|
|
95e0cb0ec2 | ||
|
|
862f942124 | ||
|
|
fdf9c1bd04 | ||
|
|
1f72d04e67 | ||
|
|
7004b55fcd | ||
|
|
ebd491dc6e | ||
|
|
cf2cc16e66 | ||
|
|
6ee3f318f8 | ||
|
|
2ba952cc73 | ||
|
|
2861280adc | ||
|
|
a5e62affe0 | ||
|
|
5acec1192d | ||
|
|
fd2e55f899 |
@@ -6,4 +6,3 @@
|
|||||||
/.gitignore export-ignore
|
/.gitignore export-ignore
|
||||||
/phpstan.neon.dist export-ignore
|
/phpstan.neon.dist export-ignore
|
||||||
/phpunit.xml.dist export-ignore
|
/phpunit.xml.dist export-ignore
|
||||||
/psalm.xml.dist export-ignore
|
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ updates:
|
|||||||
prefix: "github-actions"
|
prefix: "github-actions"
|
||||||
open-pull-requests-limit: 10
|
open-pull-requests-limit: 10
|
||||||
labels:
|
labels:
|
||||||
- "dependency"
|
- "dependencies"
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
name: "Dependabot auto-merge"
|
|
||||||
|
|
||||||
on: [pull_request_target] # yamllint disable-line rule:truthy
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: "write"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
dependabot:
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
if: "${{ github.actor == 'dependabot[bot]' }}"
|
|
||||||
steps:
|
|
||||||
- name: "Dependabot metadata"
|
|
||||||
id: "metadata"
|
|
||||||
uses: "dependabot/[email protected]"
|
|
||||||
with:
|
|
||||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
- name: "Enable auto-merge for Dependabot PRs"
|
|
||||||
if: "${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }}"
|
|
||||||
run: "gh pr merge --auto --merge \"$PR_URL\""
|
|
||||||
env:
|
|
||||||
PR_URL: "${{github.event.pull_request.html_url}}"
|
|
||||||
GITHUB_TOKEN: "${{secrets.GITHUB_TOKEN}}"
|
|
||||||
+10
-14
@@ -4,26 +4,26 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '1.x'
|
- '4.x'
|
||||||
- '2.x'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: PHP ${{ matrix.php }}
|
name: PHP ${{ matrix.php }}
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
php:
|
php:
|
||||||
- "8.1"
|
- "8.3"
|
||||||
- "8.2"
|
- "8.4"
|
||||||
dependencies:
|
- "8.5"
|
||||||
- "lowest"
|
include:
|
||||||
- "highest"
|
- php: "8.6"
|
||||||
|
composer-options: "--ignore-platform-req=php+"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
@@ -33,9 +33,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- uses: "ramsey/composer-install@v1"
|
- uses: "ramsey/composer-install@v4"
|
||||||
with:
|
with:
|
||||||
dependency-versions: "${{ matrix.dependencies }}"
|
|
||||||
composer-options: "${{ matrix.composer-options }}"
|
composer-options: "${{ matrix.composer-options }}"
|
||||||
|
|
||||||
- name: Setup problem matchers for PHP
|
- name: Setup problem matchers for PHP
|
||||||
@@ -44,9 +43,6 @@ jobs:
|
|||||||
- name: Run PHPStan
|
- name: Run PHPStan
|
||||||
run: vendor/bin/phpstan analyse --error-format=github
|
run: vendor/bin/phpstan analyse --error-format=github
|
||||||
|
|
||||||
- name: Run Psalm
|
|
||||||
run: vendor/bin/psalm --output-format=github
|
|
||||||
|
|
||||||
- name: Setup Problem Matchers for PHPUnit
|
- name: Setup Problem Matchers for PHPUnit
|
||||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,3 @@
|
|||||||
/composer.lock
|
/composer.lock
|
||||||
/phpstan.neon
|
/phpstan.neon
|
||||||
/phpunit.xml
|
/phpunit.xml
|
||||||
/psalm.xml
|
|
||||||
|
|||||||
@@ -1,5 +1,31 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 4.0.0 - 2026-08-23
|
||||||
|
|
||||||
|
* Dropped support for PHP <8.3.
|
||||||
|
* Removed the deprecated `Beste\Clock` interface. Clock implementations now implement
|
||||||
|
`Psr\Clock\ClockInterface` directly.
|
||||||
|
* `WrappingClock` will throw an `InvalidArgumentException` if the given object doesn't behave like
|
||||||
|
a PSR-20 clock and will throw an `UnexpectedValueException` if a later call does not return
|
||||||
|
`DateTimeImmutable`.
|
||||||
|
|
||||||
|
## 3.1.0 - 2026-08-22
|
||||||
|
|
||||||
|
Deprecated `Beste\Clock` in favor of `Psr\Clock\ClockInterface`. The implementations continue to implement
|
||||||
|
the deprecated interface for backwards compatibility. Please type against `Psr\Clock\ClockInterface`.
|
||||||
|
`Beste\Clock` will be removed in 4.0.
|
||||||
|
|
||||||
|
## 3.0.0 - 2022-11-26
|
||||||
|
This release replaces `stella-maris/clock` with `psr/clock`.
|
||||||
|
|
||||||
|
## 2.3.1 - 2022-11-25
|
||||||
|
This release reverts the change to implement `psr/clock` directly, to not break dependents who rely on `stella-maris/clock`
|
||||||
|
|
||||||
|
## 2.3.0 - 2022-11-25
|
||||||
|
This release re-introduces support for PHP ^8.0 and implements the freshly released `psr/clock` (PSR-20) directly.
|
||||||
|
|
||||||
## 2.2.0 - 2022-11-04
|
## 2.2.0 - 2022-11-04
|
||||||
This release drops support for PHP <8.1.
|
This release drops support for PHP <8.1.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
[](https://packagist.org/packages/beste/clock)
|
[](https://packagist.org/packages/beste/clock)
|
||||||
[](https://github.com/beste/clock/actions/workflows/tests.yml)
|
[](https://github.com/beste/clock/actions/workflows/tests.yml)
|
||||||
|
|
||||||
A collection of Clock implementations.
|
A collection of [PSR-20](https://www.php-fig.org/psr/psr-20/) Clock implementations.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
@@ -114,8 +114,8 @@ printf("\nAfter turning back the clock 5 minutes, it's %s", $frozenClock->now()-
|
|||||||
|
|
||||||
### `MinuteClock`
|
### `MinuteClock`
|
||||||
|
|
||||||
In some cases, microseconds, milliseconds, or even seconds are too precise for some use cases - sometimes it's just
|
In some cases, microseconds, milliseconds, or even seconds are too precise. Sometimes it is enough to know that
|
||||||
enough if something happened in the same minute. Using the minute
|
something happened within the same minute. `MinuteClock` removes seconds and fractions of a second from another clock.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
# examples/minute_clock.php
|
# examples/minute_clock.php
|
||||||
@@ -141,10 +141,8 @@ printf("For %s, the minute clock still returns %s\n",
|
|||||||
|
|
||||||
### `WrappingClock`
|
### `WrappingClock`
|
||||||
|
|
||||||
If you already have an object with a `now()` method returning a `DateTimeImmutable` object, you can wrap it
|
If you already have an object with a `now()` method returning a `DateTimeImmutable`, you can wrap it in a
|
||||||
in a `WrappingClock` to make it a "real" Clock.
|
`WrappingClock` to make it a PSR-20 clock.
|
||||||
|
|
||||||
as a "real" clock.
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
# examples/wrapping_clock.php
|
# examples/wrapping_clock.php
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
## Security contact information
|
||||||
|
|
||||||
|
To report a security vulnerability, please use the
|
||||||
|
[Tidelift security contact](https://tidelift.com/security).
|
||||||
|
Tidelift will coordinate the fix and disclosure.
|
||||||
+11
-18
@@ -11,29 +11,24 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "~8.1.0 || ~8.2.0",
|
"php": "^8.3",
|
||||||
"stella-maris/clock": "^0.1.6"
|
"psr/clock": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/extension-installer": "^1.2",
|
"phpstan/extension-installer": "^1.4.1",
|
||||||
"phpstan/phpstan": "^1.9.1",
|
"phpstan/phpstan": "^2.1",
|
||||||
"phpstan/phpstan-phpunit": "^1.2.2",
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
"phpstan/phpstan-strict-rules": "^1.4.4",
|
"phpstan/phpstan-strict-rules": "^2.0",
|
||||||
"phpunit/phpunit": "^9.5.26",
|
"phpunit/phpunit": "^12.5"
|
||||||
"psalm/plugin-phpunit": "^0.16.1",
|
|
||||||
"vimeo/psalm": "^4.29"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Beste\\Clock\\": "src/Clock"
|
"Beste\\Clock\\": "src"
|
||||||
},
|
}
|
||||||
"files": [
|
|
||||||
"src/Clock.php"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Beste\\Clock\\Tests\\": "tests/Clock"
|
"Beste\\Clock\\Tests\\": "tests"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
@@ -48,11 +43,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": [
|
"test": [
|
||||||
"@phpstan",
|
"@phpstan",
|
||||||
"@psalm",
|
|
||||||
"@phpunit"
|
"@phpunit"
|
||||||
],
|
],
|
||||||
"phpunit": "vendor/bin/phpunit",
|
"phpunit": "vendor/bin/phpunit",
|
||||||
"phpstan": "vendor/bin/phpstan analyse",
|
"phpstan": "vendor/bin/phpstan analyse"
|
||||||
"psalm": "vendor/bin/psalm"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd"
|
||||||
bootstrap="vendor/autoload.php"
|
bootstrap="vendor/autoload.php"
|
||||||
cacheResultFile=".build/phpunit/phpunit.cache"
|
cacheDirectory=".build/phpunit/cache"
|
||||||
beStrictAboutCoversAnnotation="true"
|
beStrictAboutCoverageMetadata="true"
|
||||||
colors="true"
|
colors="true"
|
||||||
>
|
>
|
||||||
<testsuites>
|
<testsuites>
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<coverage>
|
<source>
|
||||||
<include>
|
<include>
|
||||||
<directory>src/Clock</directory>
|
<directory>src</directory>
|
||||||
</include>
|
</include>
|
||||||
</coverage>
|
</source>
|
||||||
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<psalm
|
|
||||||
xmlns="https://getpsalm.org/schema/config"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
|
||||||
cacheDirectory=".build/psalm"
|
|
||||||
errorLevel="1"
|
|
||||||
resolveFromConfigFile="true"
|
|
||||||
>
|
|
||||||
<projectFiles>
|
|
||||||
<directory name="src" />
|
|
||||||
<directory name="tests" />
|
|
||||||
<ignoreFiles>
|
|
||||||
<directory name="vendor" />
|
|
||||||
</ignoreFiles>
|
|
||||||
</projectFiles>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
|
|
||||||
</plugins>
|
|
||||||
</psalm>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Beste;
|
|
||||||
|
|
||||||
use StellaMaris\Clock\ClockInterface;
|
|
||||||
|
|
||||||
interface Clock extends ClockInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Beste\Clock;
|
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
|
||||||
use StellaMaris\Clock\ClockInterface;
|
|
||||||
|
|
||||||
final class WrappingClock implements Clock
|
|
||||||
{
|
|
||||||
private ClockInterface $wrappedClock;
|
|
||||||
|
|
||||||
private function __construct(ClockInterface $wrappedClock)
|
|
||||||
{
|
|
||||||
$this->wrappedClock = $wrappedClock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function wrapping(object $clock): self
|
|
||||||
{
|
|
||||||
if ($clock instanceof ClockInterface) {
|
|
||||||
return new self($clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!method_exists($clock, 'now')) {
|
|
||||||
throw new \InvalidArgumentException('$clock must implement StellaMaris\Clock\ClockInterface or have a now() method');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($clock->now() instanceof DateTimeImmutable)) {
|
|
||||||
throw new \InvalidArgumentException('$clock->now() must return a DateTimeImmutable');
|
|
||||||
}
|
|
||||||
|
|
||||||
$wrappedClock = new class($clock) implements ClockInterface {
|
|
||||||
private object $clock;
|
|
||||||
|
|
||||||
public function __construct(object $clock)
|
|
||||||
{
|
|
||||||
$this->clock = $clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function now(): \DateTimeImmutable
|
|
||||||
{
|
|
||||||
assert(method_exists($this->clock, 'now'));
|
|
||||||
|
|
||||||
$now = $this->clock->now();
|
|
||||||
|
|
||||||
assert($now instanceof \DateTimeImmutable);
|
|
||||||
|
|
||||||
return $now;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new self($wrappedClock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function now(): DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->wrappedClock->now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,12 +4,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Beste\Clock;
|
namespace Beste\Clock;
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use StellaMaris\Clock\ClockInterface;
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
final class FrozenClock implements Clock
|
final class FrozenClock implements ClockInterface
|
||||||
{
|
{
|
||||||
private DateTimeImmutable $frozenAt;
|
private DateTimeImmutable $frozenAt;
|
||||||
|
|
||||||
@@ -4,13 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Beste\Clock;
|
namespace Beste\Clock;
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use Psr\Clock\ClockInterface;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
final class LocalizedClock implements Clock
|
final class LocalizedClock implements ClockInterface
|
||||||
{
|
{
|
||||||
private DateTimeZone $timeZone;
|
private DateTimeZone $timeZone;
|
||||||
|
|
||||||
@@ -19,10 +19,7 @@ final class LocalizedClock implements Clock
|
|||||||
$this->timeZone = $timeZone;
|
$this->timeZone = $timeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function in(DateTimeZone|string $timeZone): self
|
||||||
* @param DateTimeZone|string $timeZone
|
|
||||||
*/
|
|
||||||
public static function in($timeZone): self
|
|
||||||
{
|
{
|
||||||
if (is_string($timeZone)) {
|
if (is_string($timeZone)) {
|
||||||
try {
|
try {
|
||||||
@@ -4,11 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Beste\Clock;
|
namespace Beste\Clock;
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use StellaMaris\Clock\ClockInterface;
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
final class MinuteClock implements Clock
|
final class MinuteClock implements ClockInterface
|
||||||
{
|
{
|
||||||
private ClockInterface $clock;
|
private ClockInterface $clock;
|
||||||
|
|
||||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Beste\Clock;
|
namespace Beste\Clock;
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
final class SystemClock implements Clock
|
final class SystemClock implements ClockInterface
|
||||||
{
|
{
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
@@ -4,11 +4,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Beste\Clock;
|
namespace Beste\Clock;
|
||||||
|
|
||||||
use Beste\Clock;
|
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
final class UTCClock implements Clock
|
final class UTCClock implements ClockInterface
|
||||||
{
|
{
|
||||||
private DateTimeZone $timeZone;
|
private DateTimeZone $timeZone;
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Beste\Clock;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Psr\Clock\ClockInterface;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
final class WrappingClock implements ClockInterface
|
||||||
|
{
|
||||||
|
private ClockInterface $wrappedClock;
|
||||||
|
|
||||||
|
private function __construct(ClockInterface $wrappedClock)
|
||||||
|
{
|
||||||
|
$this->wrappedClock = $wrappedClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException when the given object doesn't behave like a clock.
|
||||||
|
*/
|
||||||
|
public static function wrapping(object $clock): self
|
||||||
|
{
|
||||||
|
if ($clock instanceof ClockInterface) {
|
||||||
|
return new self($clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method_exists($clock, 'now')) {
|
||||||
|
throw new InvalidArgumentException('$clock must implement Psr\Clock\ClockInterface or have a now() method');
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = new ReflectionMethod($clock, 'now');
|
||||||
|
|
||||||
|
if (!$method->isPublic() || $method->getNumberOfRequiredParameters() > 0) {
|
||||||
|
throw new InvalidArgumentException('$clock->now() must be public and accept no required parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
$wrappedClock = new class($method->getClosure($clock)) implements ClockInterface {
|
||||||
|
private Closure $now;
|
||||||
|
|
||||||
|
public function __construct(Closure $now)
|
||||||
|
{
|
||||||
|
$this->now = $now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function now(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$now = ($this->now)();
|
||||||
|
|
||||||
|
if (!$now instanceof DateTimeImmutable) {
|
||||||
|
throw new UnexpectedValueException('$clock->now() must return a DateTimeImmutable');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $now;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new self($wrappedClock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function now(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->wrappedClock->now();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Beste\Clock\Tests;
|
|
||||||
|
|
||||||
use Beste\Clock\FrozenClock;
|
|
||||||
use Beste\Clock\WrappingClock;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
* @coversDefaultClass \Beste\Clock\WrappingClock
|
|
||||||
*/
|
|
||||||
final class WrappingClockTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::create
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itWrapsAClockInterface(): void
|
|
||||||
{
|
|
||||||
$clock = FrozenClock::fromUTC();
|
|
||||||
|
|
||||||
$wrappedClock = WrappingClock::wrapping($clock);
|
|
||||||
|
|
||||||
self::assertSame(
|
|
||||||
$clock->now()->format(DATE_ATOM),
|
|
||||||
$wrappedClock->now()->format(DATE_ATOM)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::create
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itWrapsAnObjectWithANowMethod(): void
|
|
||||||
{
|
|
||||||
$now = FrozenClock::fromUTC()->now();
|
|
||||||
|
|
||||||
$clock = new class($now) {
|
|
||||||
private \DateTimeImmutable $now;
|
|
||||||
|
|
||||||
public function __construct(\DateTimeImmutable $now)
|
|
||||||
{
|
|
||||||
$this->now = $now;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function now(): \DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->now;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$wrappedClock = WrappingClock::wrapping($clock);
|
|
||||||
|
|
||||||
self::assertSame(
|
|
||||||
$now->format(DATE_ATOM),
|
|
||||||
$wrappedClock->now()->format(DATE_ATOM)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @covers ::create
|
|
||||||
*/
|
|
||||||
public function itRejectsObjectsWithANowMethodReturningANonDateTimeImmutable(): void
|
|
||||||
{
|
|
||||||
$clock = new class() {
|
|
||||||
public function now(): string
|
|
||||||
{
|
|
||||||
return 'foo';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->expectException(\InvalidArgumentException::class);
|
|
||||||
$this->expectExceptionMessage('$clock->now() must return a DateTimeImmutable');
|
|
||||||
|
|
||||||
WrappingClock::wrapping($clock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,21 +6,18 @@ namespace Beste\Clock\Tests;
|
|||||||
|
|
||||||
use Beste\Clock\FrozenClock;
|
use Beste\Clock\FrozenClock;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use StellaMaris\Clock\ClockInterface;
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @coversDefaultClass \Beste\Clock\FrozenClock
|
|
||||||
*/
|
*/
|
||||||
|
#[CoversClass(FrozenClock::class)]
|
||||||
final class FrozenClockTest extends TestCase
|
final class FrozenClockTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::at
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itFreezesTime(): void
|
public function itFreezesTime(): void
|
||||||
{
|
{
|
||||||
$now = new DateTimeImmutable('2021-03-21 22:16:00');
|
$now = new DateTimeImmutable('2021-03-21 22:16:00');
|
||||||
@@ -29,14 +26,7 @@ final class FrozenClockTest extends TestCase
|
|||||||
self::assertEquals($now, $clock->now());
|
self::assertEquals($now, $clock->now());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @uses \Beste\Clock\FrozenClock::__construct
|
|
||||||
* @uses \Beste\Clock\FrozenClock::fromUTC()
|
|
||||||
*
|
|
||||||
* @covers ::now()
|
|
||||||
*/
|
|
||||||
public function itReturnsAnEqualNowButNotTheSame(): void
|
public function itReturnsAnEqualNowButNotTheSame(): void
|
||||||
{
|
{
|
||||||
$clock = FrozenClock::fromUTC();
|
$clock = FrozenClock::fromUTC();
|
||||||
@@ -48,14 +38,7 @@ final class FrozenClockTest extends TestCase
|
|||||||
self::assertNotSame($first, $second);
|
self::assertNotSame($first, $second);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @uses \Beste\Clock\FrozenClock::__construct
|
|
||||||
* @uses \Beste\Clock\FrozenClock::now
|
|
||||||
*
|
|
||||||
* @covers ::withNowFrom
|
|
||||||
*/
|
|
||||||
public function itFreezesTimeFromAnotherClock(): void
|
public function itFreezesTimeFromAnotherClock(): void
|
||||||
{
|
{
|
||||||
$now = new DateTimeImmutable('now');
|
$now = new DateTimeImmutable('now');
|
||||||
@@ -71,14 +54,7 @@ final class FrozenClockTest extends TestCase
|
|||||||
self::assertEquals($now, $frozenClock->now());
|
self::assertEquals($now, $frozenClock->now());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @uses \Beste\Clock\FrozenClock::__construct
|
|
||||||
* @uses \Beste\Clock\FrozenClock::now
|
|
||||||
*
|
|
||||||
* @covers ::fromUTC
|
|
||||||
*/
|
|
||||||
public function itFreezesTheCurrentUTCTime(): void
|
public function itFreezesTheCurrentUTCTime(): void
|
||||||
{
|
{
|
||||||
$clock = FrozenClock::fromUTC();
|
$clock = FrozenClock::fromUTC();
|
||||||
@@ -87,15 +63,7 @@ final class FrozenClockTest extends TestCase
|
|||||||
self::assertEquals($clock->now(), $clock->now());
|
self::assertEquals($clock->now(), $clock->now());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @uses \Beste\Clock\FrozenClock::__construct
|
|
||||||
* @uses \Beste\Clock\FrozenClock::at
|
|
||||||
* @uses \Beste\Clock\FrozenClock::now
|
|
||||||
*
|
|
||||||
* @covers ::setTo
|
|
||||||
*/
|
|
||||||
public function itCanBeSet(): void
|
public function itCanBeSet(): void
|
||||||
{
|
{
|
||||||
$now = new DateTimeImmutable('2021-03-21 18:18:18');
|
$now = new DateTimeImmutable('2021-03-21 18:18:18');
|
||||||
@@ -7,18 +7,17 @@ namespace Beste\Clock\Tests;
|
|||||||
use Beste\Clock\LocalizedClock;
|
use Beste\Clock\LocalizedClock;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @coversDefaultClass \Beste\Clock\LocalizedClock
|
|
||||||
*/
|
*/
|
||||||
|
#[CoversClass(LocalizedClock::class)]
|
||||||
final class LocalizedClockTest extends TestCase
|
final class LocalizedClockTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
* @covers ::in
|
|
||||||
*/
|
|
||||||
public function itRejectsAnInvalidTimeZone(): void
|
public function itRejectsAnInvalidTimeZone(): void
|
||||||
{
|
{
|
||||||
$this->expectException(InvalidArgumentException::class);
|
$this->expectException(InvalidArgumentException::class);
|
||||||
@@ -26,12 +25,7 @@ final class LocalizedClockTest extends TestCase
|
|||||||
LocalizedClock::in('invalid');
|
LocalizedClock::in('invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::in
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itUsesTheGivenTimeZone(): void
|
public function itUsesTheGivenTimeZone(): void
|
||||||
{
|
{
|
||||||
$timeZone = new DateTimeZone('Asia/Bangkok');
|
$timeZone = new DateTimeZone('Asia/Bangkok');
|
||||||
@@ -41,12 +35,7 @@ final class LocalizedClockTest extends TestCase
|
|||||||
self::assertSame($timeZone->getName(), $now->getTimezone()->getName());
|
self::assertSame($timeZone->getName(), $now->getTimezone()->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::in
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itAcceptsTheTimeZoneAsAString(): void
|
public function itAcceptsTheTimeZoneAsAString(): void
|
||||||
{
|
{
|
||||||
$timeZone = 'Pacific/Guam';
|
$timeZone = 'Pacific/Guam';
|
||||||
@@ -6,30 +6,23 @@ namespace Beste\Clock\Tests;
|
|||||||
|
|
||||||
use Beste\Clock\MinuteClock;
|
use Beste\Clock\MinuteClock;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use StellaMaris\Clock\ClockInterface;
|
use Psr\Clock\ClockInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @coversDefaultClass \Beste\Clock\MinuteClock
|
|
||||||
*/
|
*/
|
||||||
|
#[CoversClass(MinuteClock::class)]
|
||||||
final class MinuteClockTest extends TestCase
|
final class MinuteClockTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
#[DataProvider('dateTimeStringProvider')]
|
||||||
*
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::wrapping
|
|
||||||
* @covers ::now
|
|
||||||
* @covers ::floor
|
|
||||||
*
|
|
||||||
* @uses \Beste\Clock\FrozenClock
|
|
||||||
*
|
|
||||||
* @dataProvider dateTimeStringProvider
|
|
||||||
*/
|
|
||||||
public function itDiscardsEverythingSmallerThanMinutes(string $format, string $input, string $expected): void
|
public function itDiscardsEverythingSmallerThanMinutes(string $format, string $input, string $expected): void
|
||||||
{
|
{
|
||||||
$mockClock = $this->createMock(ClockInterface::class);
|
$mockClock = self::createStub(ClockInterface::class);
|
||||||
$mockClock->method('now')->willReturn(new DateTimeImmutable($input));
|
$mockClock->method('now')->willReturn(new DateTimeImmutable($input));
|
||||||
|
|
||||||
// Just to be sure that the test input is valid ^^
|
// Just to be sure that the test input is valid ^^
|
||||||
@@ -43,7 +36,7 @@ final class MinuteClockTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @return array<string, string[]>
|
* @return array<string, string[]>
|
||||||
*/
|
*/
|
||||||
public function dateTimeStringProvider(): array
|
public static function dateTimeStringProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'microseconds' => [
|
'microseconds' => [
|
||||||
@@ -5,12 +5,14 @@ declare(strict_types=1);
|
|||||||
namespace Beste\Clock\Tests;
|
namespace Beste\Clock\Tests;
|
||||||
|
|
||||||
use Beste\Clock\SystemClock;
|
use Beste\Clock\SystemClock;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @coversDefaultClass \Beste\Clock\SystemClock
|
|
||||||
*/
|
*/
|
||||||
|
#[CoversClass(SystemClock::class)]
|
||||||
final class SystemClockTest extends TestCase
|
final class SystemClockTest extends TestCase
|
||||||
{
|
{
|
||||||
private string $defaultTimeZone;
|
private string $defaultTimeZone;
|
||||||
@@ -25,16 +27,10 @@ final class SystemClockTest extends TestCase
|
|||||||
date_default_timezone_set($this->defaultTimeZone);
|
date_default_timezone_set($this->defaultTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::create
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itUsesTheSystemTimeZone(): void
|
public function itUsesTheSystemTimeZone(): void
|
||||||
{
|
{
|
||||||
$timeZone = 'Europe/Berlin';
|
$timeZone = $this->defaultTimeZone === 'Europe/Berlin' ? 'UTC' : 'Europe/Berlin';
|
||||||
self::assertNotSame($timeZone, $this->defaultTimeZone);
|
self::assertNotSame($timeZone, $this->defaultTimeZone);
|
||||||
|
|
||||||
date_default_timezone_set($timeZone);
|
date_default_timezone_set($timeZone);
|
||||||
@@ -5,12 +5,14 @@ declare(strict_types=1);
|
|||||||
namespace Beste\Clock\Tests;
|
namespace Beste\Clock\Tests;
|
||||||
|
|
||||||
use Beste\Clock\UTCClock;
|
use Beste\Clock\UTCClock;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @coversDefaultClass \Beste\Clock\UTCClock
|
|
||||||
*/
|
*/
|
||||||
|
#[CoversClass(UTCClock::class)]
|
||||||
final class UTCClockTest extends TestCase
|
final class UTCClockTest extends TestCase
|
||||||
{
|
{
|
||||||
private string $defaultTimeZone;
|
private string $defaultTimeZone;
|
||||||
@@ -25,13 +27,7 @@ final class UTCClockTest extends TestCase
|
|||||||
date_default_timezone_set($this->defaultTimeZone);
|
date_default_timezone_set($this->defaultTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[Test]
|
||||||
* @test
|
|
||||||
*
|
|
||||||
* @covers ::__construct
|
|
||||||
* @covers ::create
|
|
||||||
* @covers ::now
|
|
||||||
*/
|
|
||||||
public function itUsesUTCRegardlessOfTheSystemTimeZone(): void
|
public function itUsesUTCRegardlessOfTheSystemTimeZone(): void
|
||||||
{
|
{
|
||||||
date_default_timezone_set('Europe/Berlin');
|
date_default_timezone_set('Europe/Berlin');
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Beste\Clock\Tests;
|
||||||
|
|
||||||
|
use Beste\Clock\FrozenClock;
|
||||||
|
use Beste\Clock\WrappingClock;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeZone;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\Attributes\UsesClass;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
#[CoversClass(WrappingClock::class)]
|
||||||
|
#[UsesClass(FrozenClock::class)]
|
||||||
|
final class WrappingClockTest extends TestCase
|
||||||
|
{
|
||||||
|
#[Test]
|
||||||
|
public function itWrapsAClockInterface(): void
|
||||||
|
{
|
||||||
|
$clock = FrozenClock::fromUTC();
|
||||||
|
|
||||||
|
$wrappedClock = WrappingClock::wrapping($clock);
|
||||||
|
|
||||||
|
self::assertSame(
|
||||||
|
$clock->now()->format(DATE_ATOM),
|
||||||
|
$wrappedClock->now()->format(DATE_ATOM)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itWrapsAnObjectWithANowMethod(): void
|
||||||
|
{
|
||||||
|
$now = FrozenClock::fromUTC()->now();
|
||||||
|
|
||||||
|
$clock = new class($now) {
|
||||||
|
private DateTimeImmutable $now;
|
||||||
|
|
||||||
|
public function __construct(DateTimeImmutable $now)
|
||||||
|
{
|
||||||
|
$this->now = $now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function now(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->now;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$wrappedClock = WrappingClock::wrapping($clock);
|
||||||
|
|
||||||
|
self::assertSame(
|
||||||
|
$now->format(DATE_ATOM),
|
||||||
|
$wrappedClock->now()->format(DATE_ATOM)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itDoesNotCallNowWhileWrapping(): void
|
||||||
|
{
|
||||||
|
$clock = new class() {
|
||||||
|
public int $calls = 0;
|
||||||
|
|
||||||
|
public function now(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
++$this->calls;
|
||||||
|
|
||||||
|
return new DateTimeImmutable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$wrappedClock = WrappingClock::wrapping($clock);
|
||||||
|
|
||||||
|
self::assertSame(0, $clock->calls);
|
||||||
|
|
||||||
|
$wrappedClock->now();
|
||||||
|
|
||||||
|
self::assertSame(1, $clock->calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itRejectsObjectsWithANowMethodReturningANonDateTimeImmutable(): void
|
||||||
|
{
|
||||||
|
$clock = new class() {
|
||||||
|
public function now(): string
|
||||||
|
{
|
||||||
|
return 'foo';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->expectException(UnexpectedValueException::class);
|
||||||
|
$this->expectExceptionMessage('$clock->now() must return a DateTimeImmutable');
|
||||||
|
|
||||||
|
WrappingClock::wrapping($clock)->now();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itRejectsObjectsWithoutANowMethod(): void
|
||||||
|
{
|
||||||
|
$clock = new class() {
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage('$clock must implement Psr\Clock\ClockInterface or have a now() method');
|
||||||
|
|
||||||
|
WrappingClock::wrapping($clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itRejectsObjectsWithANonPublicNowMethod(): void
|
||||||
|
{
|
||||||
|
$clock = new class() {
|
||||||
|
protected function now(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return new DateTimeImmutable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage('$clock->now() must be public and accept no required parameters');
|
||||||
|
|
||||||
|
WrappingClock::wrapping($clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function itRejectsObjectsWithANowMethodRequiringArguments(): void
|
||||||
|
{
|
||||||
|
$clock = new class() {
|
||||||
|
public function now(string $timeZone): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return new DateTimeImmutable('now', new DateTimeZone($timeZone));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage('$clock->now() must be public and accept no required parameters');
|
||||||
|
|
||||||
|
WrappingClock::wrapping($clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user