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(<<