diff --git a/composer.json b/composer.json
index 00fb1c5d48..f4c4957df6 100644
--- a/composer.json
+++ b/composer.json
@@ -38,7 +38,6 @@
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5|^9.6",
- "symfony/phpunit-bridge": "^5.2|^6.0|^7.0",
"vimeo/psalm": "^4.17"
},
"suggest": {
diff --git a/phpstan.neon b/phpstan.neon
index 91af9c48e5..61e18b96c3 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -10,6 +10,7 @@ parameters:
excludePaths:
- tests/resources
- tests/Fixtures
+ - src/Util/ClockMock.php
dynamicConstantNames:
- Monolog\Logger::API
bootstrapFiles:
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d064f87759..8d5384d667 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -34,10 +34,6 @@
-
-
-
-
diff --git a/psalm.xml.dist b/psalm.xml.dist
index dc733ed56b..2ac6e7397e 100644
--- a/psalm.xml.dist
+++ b/psalm.xml.dist
@@ -11,6 +11,7 @@
+
diff --git a/src/Util/ClockMock.php b/src/Util/ClockMock.php
new file mode 100644
index 0000000000..004291d39e
--- /dev/null
+++ b/src/Util/ClockMock.php
@@ -0,0 +1,202 @@
+
+ * @author Dominic Tubach
+ */
+class ClockMock
+{
+ private static $now;
+
+ public static function withClockMock($enable = null): ?bool
+ {
+ if ($enable === null) {
+ return self::$now !== null;
+ }
+
+ self::$now = is_numeric($enable) ? (float) $enable : ($enable ? microtime(true) : null);
+
+ return null;
+ }
+
+ public static function time(): int
+ {
+ if (self::$now === null) {
+ return time();
+ }
+
+ return (int) self::$now;
+ }
+
+ public static function sleep($s): int
+ {
+ if (self::$now === null) {
+ return sleep($s);
+ }
+
+ self::$now += (int) $s;
+
+ return 0;
+ }
+
+ public static function usleep($us): void
+ {
+ if (self::$now === null) {
+ usleep($us);
+ } else {
+ self::$now += $us / 1000000;
+ }
+ }
+
+ /**
+ * @return string|float
+ */
+ public static function microtime($asFloat = false)
+ {
+ if (self::$now === null) {
+ return microtime($asFloat);
+ }
+
+ if ($asFloat) {
+ return self::$now;
+ }
+
+ return \sprintf('%0.6f00 %d', self::$now - (int) self::$now, (int) self::$now);
+ }
+
+ public static function date($format, $timestamp = null): string
+ {
+ if ($timestamp === null) {
+ $timestamp = self::time();
+ }
+
+ return date($format, $timestamp);
+ }
+
+ public static function gmdate($format, $timestamp = null): string
+ {
+ if ($timestamp === null) {
+ $timestamp = self::time();
+ }
+
+ return gmdate($format, $timestamp);
+ }
+
+ /**
+ * @return array|int|float
+ */
+ public static function hrtime($asNumber = false)
+ {
+ $ns = (self::$now - (int) self::$now) * 1000000000;
+
+ if ($asNumber) {
+ $number = \sprintf('%d%d', (int) self::$now, $ns);
+
+ return \PHP_INT_SIZE === 8 ? (int) $number : (float) $number;
+ }
+
+ return [(int) self::$now, (int) $ns];
+ }
+
+ /**
+ * @return false|int
+ */
+ public static function strtotime(string $datetime, ?int $timestamp = null)
+ {
+ if ($timestamp === null) {
+ $timestamp = self::time();
+ }
+
+ return strtotime($datetime, $timestamp);
+ }
+
+ public static function register($class): void
+ {
+ $self = static::class;
+
+ $mockedNs = [substr($class, 0, strrpos($class, '\\'))];
+ if (strpos($class, '\\Tests\\') > 0) {
+ $ns = str_replace('\\Tests\\', '\\', $class);
+ $mockedNs[] = substr($ns, 0, strrpos($ns, '\\'));
+ } elseif (strpos($class, 'Tests\\') === 0) {
+ $mockedNs[] = substr($class, 6, strrpos($class, '\\') - 6);
+ }
+ foreach ($mockedNs as $ns) {
+ if (\function_exists($ns . '\time')) {
+ continue;
+ }
+ eval(<<