From cf726882b16243be4de3b4ee39a1c6543a142b74 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 20 May 2026 06:39:28 +0000 Subject: [PATCH] Add Carbonite for time manipulation in tests Install kylekatarnls/carbonite as a dev dependency and enable BespinTimeMocking so each test gets a clean timeline. Add Pest helpers fakeAsync() and tick(), plus unit tests for freeze, accelerate, decelerate, elapse, and speed. Closes #10 Co-authored-by: Theron Smith --- composer.json | 1 + composer.lock | 67 ++++++++++++++++++++++++++++++++++-- tests/Pest.php | 27 +++++++++++++++ tests/Unit/CarboniteTest.php | 49 ++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/CarboniteTest.php diff --git a/composer.json b/composer.json index 0792205..bf608f2 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "barryvdh/laravel-debugbar": "^3.14", "fakerphp/faker": "^1.23", "filament/upgrade": "^4.0", + "kylekatarnls/carbonite": "^2.0", "laravel/boost": "^1.0", "laravel/pail": "^1.1", "laravel/pint": "^1.13", diff --git a/composer.lock b/composer.lock index b39749f..9bd4ca9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "77e6c447e0609e8684de93d371c747b0", + "content-hash": "d55bd8b0869069ae0155ab26531c17da", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -9586,6 +9586,69 @@ }, "time": "2025-03-19T14:43:43+00:00" }, + { + "name": "kylekatarnls/carbonite", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/kylekatarnls/carbonite.git", + "reference": "46c85a583861ca4af43aef86665a9728964866a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kylekatarnls/carbonite/zipball/46c85a583861ca4af43aef86665a9728964866a0", + "reference": "46c85a583861ca4af43aef86665a9728964866a0", + "shasum": "" + }, + "require": { + "nesbot/carbon": "^3.0.2", + "php": "^8.2", + "psr/clock": "^1.0" + }, + "require-dev": { + "phan/phan": "^5.4.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/phpstan": "^1.10.58", + "phpunit/phpunit": "^11.0.3", + "squizlabs/php_codesniffer": "^3.8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "carbon@selfbuild.fr" + } + ], + "description": "Freeze, accelerate, slow down time and many more with Carbon.", + "support": { + "issues": "https://github.com/kylekatarnls/carbonite/issues", + "source": "https://github.com/kylekatarnls/carbonite/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-21T10:39:11+00:00" + }, { "name": "laravel/boost", "version": "v1.0.18", @@ -12733,5 +12796,5 @@ "php": "^8.3" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/tests/Pest.php b/tests/Pest.php index 60f04a4..f621a7b 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,8 @@ in('Feature', 'Unit'); + pest()->extend(Tests\TestCase::class) // ->use(Illuminate\Foundation\Testing\RefreshDatabase::class) ->in('Feature'); @@ -45,3 +50,25 @@ function something() { // .. } + +/** + * Run a callback with time frozen, then restore the real timeline. + */ +function fakeAsync(callable $callback): mixed +{ + Carbonite::freeze(); + + try { + return $callback(); + } finally { + Carbonite::release(); + } +} + +/** + * Advance the fake timeline by the given number of milliseconds. + */ +function tick(int $milliseconds): void +{ + Carbonite::elapse("{$milliseconds} milliseconds"); +} diff --git a/tests/Unit/CarboniteTest.php b/tests/Unit/CarboniteTest.php new file mode 100644 index 0000000..8e2646d --- /dev/null +++ b/tests/Unit/CarboniteTest.php @@ -0,0 +1,49 @@ +toDateTimeString())->toBe('2024-01-15 10:00:00') + ->and(Carbonite::speed())->toBe(0.0); +}); + +it('accelerates the fake timeline', function () { + Carbonite::freeze('2024-01-01 00:00:00'); + Carbonite::speed(2); + + expect(Carbonite::accelerate(3))->toBe(6.0); +}); + +it('decelerates the fake timeline', function () { + Carbonite::freeze('2024-01-01 00:00:00'); + Carbonite::speed(5); + + expect(Carbonite::decelerate(2))->toBe(2.5); +}); + +it('elapses time on the fake timeline', function () { + Carbonite::freeze('2024-01-01'); + Carbonite::elapse('1 month'); + + expect(Carbon::now()->format('Y-m-d'))->toBe('2024-02-01'); +}); + +it('advances time with tick inside fakeAsync', function () { + fakeAsync(function () { + $now = Carbon::now(); + + tick(2000); + + expect($now->diffForHumans())->toBe('2 seconds ago'); + }); +}); + +it('sets timeline speed with speed()', function () { + Carbonite::freeze('2024-06-01 12:00:00'); + Carbonite::speed(3); + + expect(Carbonite::speed())->toBe(3.0); +});