set(CacheItem::forSet($key, 'test-value')); expect($result)->toBeTrue(); $resultItem = $cache->get($key); expect($resultItem->isHit)->toBeTrue(); expect($resultItem->value)->toBe('test-value'); }); test('cache returns miss for non-existent key', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key = CacheKey::fromString('non-existent'); $item = $cache->get($key); expect($item->isHit)->toBeFalse(); expect($item->value)->toBeNull(); }); test('cache can check if key exists', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key = CacheKey::fromString('test-key'); $hasResult = $cache->has($key); expect($hasResult[$key->toString()])->toBeFalse(); $cache->set(CacheItem::forSet($key, 'value')); $hasResult = $cache->has($key); expect($hasResult[$key->toString()])->toBeTrue(); }); test('cache can forget keys', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key = CacheKey::fromString('test-key'); $cache->set(CacheItem::forSet($key, 'value')); $hasResult = $cache->has($key); expect($hasResult[$key->toString()])->toBeTrue(); $result = $cache->forget($key); expect($result)->toBeTrue(); $hasResult = $cache->has($key); expect($hasResult[$key->toString()])->toBeFalse(); }); test('cache can clear all entries', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key1 = CacheKey::fromString('key1'); $key2 = CacheKey::fromString('key2'); $cache->set(CacheItem::forSet($key1, 'value1')); $cache->set(CacheItem::forSet($key2, 'value2')); $result = $cache->clear(); expect($result)->toBeTrue(); $hasResult1 = $cache->has($key1); $hasResult2 = $cache->has($key2); expect($hasResult1[$key1->toString()])->toBeFalse(); expect($hasResult2[$key2->toString()])->toBeFalse(); }); test('cache remember pattern works', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key = CacheKey::fromString('test-key'); $callCount = 0; $callback = function () use (&$callCount) { $callCount++; return 'computed-value'; }; // First call should execute callback $item1 = $cache->remember($key, $callback); expect($item1->value)->toBe('computed-value'); expect($callCount)->toBe(1); // Second call should return cached value $item2 = $cache->remember($key, $callback); expect($item2->value)->toBe('computed-value'); expect($callCount)->toBe(1); // Callback not called again }); test('cache respects TTL', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); $key = CacheKey::fromString('test-key'); $ttl = Duration::fromSeconds(60); // This test would need a mock or a way to advance time // For now, just test that TTL parameter is accepted $result = $cache->set(CacheItem::forSet($key, 'value', $ttl)); expect($result)->toBeTrue(); }); test('cache can store different data types', function () { $cache = new GeneralCache(new InMemoryCache(), new PhpSerializer()); // String $stringKey = CacheKey::fromString('string'); $cache->set(CacheItem::forSet($stringKey, 'test')); expect($cache->get($stringKey)->value)->toBe('test'); // Integer $intKey = CacheKey::fromString('int'); $cache->set(CacheItem::forSet($intKey, 42)); expect($cache->get($intKey)->value)->toBe(42); // Array $arrayKey = CacheKey::fromString('array'); $cache->set(CacheItem::forSet($arrayKey, ['a' => 1, 'b' => 2])); expect($cache->get($arrayKey)->value)->toBe(['a' => 1, 'b' => 2]); // Object - stdClass becomes __PHP_Incomplete_Class when deserialized // This is expected PHP behavior with PhpSerializer $objectKey = CacheKey::fromString('object'); $obj = (object) ['test' => 'value', 'number' => 42]; $cache->set(CacheItem::forSet($objectKey, $obj)); $result = $cache->get($objectKey); // Verify object was cached (becomes __PHP_Incomplete_Class on deserialization) expect($result->value)->toBeObject(); expect($result->value::class)->toBe('__PHP_Incomplete_Class'); });