HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/tests/Unit/Cache/AppCacheTest.php
<?php

use App\Library\Cache\AppCache;
use App\Library\Cache\Cacheable;
use App\Library\Cache\CacheScope;
use Illuminate\Support\Facades\Cache;

uses(Tests\TestCase::class);

beforeEach(function () {
    Cache::flush();
    AppCache::reset();
});

function fakeCacheable(string $key, array $manifest = []): Cacheable
{
    return new class($key, $manifest) implements Cacheable {
        public function __construct(private string $key, private array $manifest) {}
        public function cacheKey(): string { return $this->key; }
        public function cacheManifest(): array { return $this->manifest; }
    };
}

test('for() returns a CacheScope', function () {
    $subject = fakeCacheable('model:Foo:1');

    expect(AppCache::for($subject))->toBeInstanceOf(CacheScope::class);
});

test('for() memoizes per scope string', function () {
    $a = fakeCacheable('model:Foo:1');
    $b = fakeCacheable('model:Foo:1');

    $h1 = AppCache::for($a);
    $h2 = AppCache::for($b);

    expect($h1)->toBe($h2);
});

test('for() lazy-loads manifest into CacheScope', function () {
    $calls = 0;
    $subject = fakeCacheable('model:Bar:1', [
        'Count' => function () use (&$calls) { $calls++; return 42; },
    ]);

    $handle = AppCache::for($subject);
    $handle->refresh();

    expect($calls)->toBe(1);
    expect($handle->read('Count'))->toBe(42);
});

test('for() parses manifest array shape with ttl', function () {
    $subject = fakeCacheable('model:TTL:1', [
        'Short' => ['compute' => fn () => 'v', 'ttl' => 60],
    ]);

    AppCache::for($subject)->refresh();
    expect(AppCache::for($subject)->read('Short'))->toBe('v');

    $this->travel(61)->seconds();
    expect(AppCache::for($subject)->read('Short', 'fallback'))->toBe('fallback');
});

test('for() rejects malformed manifest entry', function () {
    $subject = fakeCacheable('model:Bad:1', [
        'Bad' => 'not-a-closure',
    ]);

    expect(fn () => AppCache::for($subject))
        ->toThrow(InvalidArgumentException::class);
});

test('for() does not re-register entries on second call', function () {
    $calls = 0;
    $subject = fakeCacheable('model:Baz:1', [
        'A' => function () use (&$calls) { $calls++; return 1; },
    ]);

    AppCache::for($subject);
    AppCache::for($subject);
    AppCache::for($subject)->refresh();

    expect($calls)->toBe(1);
});

test('for() rejects unknown entry access', function () {
    $subject = fakeCacheable('model:Strict:1', [
        'Known' => fn () => 'v',
    ]);

    $handle = AppCache::for($subject);

    expect(fn () => $handle->read('Unknown'))
        ->toThrow(InvalidArgumentException::class, "Unknown cache entry 'Unknown'");
});

test('reset() clears process-level memoization', function () {
    $subject = fakeCacheable('reset.ns');
    $h1 = AppCache::for($subject);

    AppCache::reset();

    $h2 = AppCache::for($subject);

    expect($h1)->not->toBe($h2);
});