From c583cebf359cab2a550bbdbc65fa1c8262023c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 24 Aug 2026 11:47:39 +0200 Subject: [PATCH 1/3] test(cache-pool): assert clear() does not affect another namespace Add an optional createCachePoolWithOtherNamespace() extension point and a test that saves the same key in two pools sharing the same storage under different namespaces. The test is skipped when the implementation returns null. --- src/CachePoolTest.php | 36 ++++++++++++++++++++++++++++++++++++ tests/CachePoolTest.php | 9 +++++++++ 2 files changed, 45 insertions(+) diff --git a/src/CachePoolTest.php b/src/CachePoolTest.php index 217a2f8..03948a3 100644 --- a/src/CachePoolTest.php +++ b/src/CachePoolTest.php @@ -34,6 +34,16 @@ abstract class CachePoolTest extends TestCase */ abstract public function createCachePool(): CacheItemPoolInterface; + /** + * A second pool backed by the same storage as createCachePool(), under a different namespace. + * + * Return null when the implementation cannot provide one, the test is then skipped. + */ + public function createCachePoolWithOtherNamespace(): ?CacheItemPoolInterface + { + return null; + } + #[Before] public function setupService() { @@ -318,6 +328,32 @@ public function testClearWithDeferredItems() $this->assertFalse($this->cache->getItem('key')->isHit(), 'Deferred items must be cleared on clear(). '); } + public function testClearDoesNotAffectOtherNamespaces() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $other = $this->createCachePoolWithOtherNamespace(); + + if (null === $other) { + $this->markTestSkipped('This implementation cannot provide a second pool on the same storage with another namespace.'); + } + + $this->cache->save($this->cache->getItem('key')->set('value')); + $other->save($other->getItem('key')->set('other value')); + + $this->assertTrue($this->cache->clear(), 'clear() must return true if cache was cleared. '); + $this->assertFalse($this->cache->hasItem('key'), 'The cleared pool should be empty after it is cleared.'); + + $otherItem = $other->getItem('key'); + $this->assertTrue($otherItem->isHit(), 'Clearing a pool must not clear a pool using another namespace on the same storage.'); + $this->assertSame('other value', $otherItem->get(), 'The item stored in the other namespace must keep its own value.'); + + // The tearDownService() hook only clears $this->cache, so the other pool is cleared here. + $other->clear(); + } + public function testDeleteItem() { if (isset($this->skippedTests[__FUNCTION__])) { diff --git a/tests/CachePoolTest.php b/tests/CachePoolTest.php index 9586745..dda4adf 100644 --- a/tests/CachePoolTest.php +++ b/tests/CachePoolTest.php @@ -25,6 +25,8 @@ final class CachePoolTest extends CachePoolContract { private ?string $namespace = null; + private ?string $otherNamespace = null; + public function createCachePool(): CacheItemPoolInterface { $this->namespace ??= bin2hex(random_bytes(16)); @@ -32,6 +34,13 @@ public function createCachePool(): CacheItemPoolInterface return new ValidatingCachePool(new FilesystemAdapter($this->namespace)); } + public function createCachePoolWithOtherNamespace(): CacheItemPoolInterface + { + $this->otherNamespace ??= bin2hex(random_bytes(16)); + + return new ValidatingCachePool(new FilesystemAdapter($this->otherNamespace)); + } + public function testDataProvidersExposeCases() { self::assertNotEmpty(self::invalidKeys()); From 8d28b46262d0383121d8d136fa78ceaba362191f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 24 Aug 2026 11:47:49 +0200 Subject: [PATCH 2/3] test(taggable): make testInvalidateTags discriminating The test used overlapping tags, so an implementation that only invalidates the first tag of the list still passed. Use disjoint tags plus a control item tagged with none of the invalidated tags. --- src/TaggableCachePoolTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/TaggableCachePoolTest.php b/src/TaggableCachePoolTest.php index 3e9216e..c275239 100644 --- a/src/TaggableCachePoolTest.php +++ b/src/TaggableCachePoolTest.php @@ -287,15 +287,19 @@ public function testInvalidateTags() } $item = $this->cache->getItem('key')->set('value'); - $item->setTags(['tag1', 'tag2']); + $item->setTags(['tag1']); $this->cache->save($item); $item = $this->cache->getItem('key2')->set('value'); - $item->setTags(['tag1']); + $item->setTags(['tag2']); + $this->cache->save($item); + $item = $this->cache->getItem('key3')->set('value'); + $item->setTags(['tag3']); $this->cache->save($item); $this->cache->invalidateTags(['tag1', 'tag2']); $this->assertFalse($this->cache->hasItem('key'), 'Item should be cleared when tag is invalidated'); $this->assertFalse($this->cache->hasItem('key2'), 'Item should be cleared when tag is invalidated'); + $this->assertTrue($this->cache->hasItem('key3'), 'An item tagged with none of the invalidated tags must survive'); // Create a new item (no tags) $item = $this->cache->getItem('key')->set('value'); From e61cecb0e6b79c9291269cede4a1700a6e03c76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 24 Aug 2026 11:47:49 +0200 Subject: [PATCH 3/3] test(taggable): assert deleteItem() returns true for a tagged item The return value was ignored, so an implementation returning false while the deletion actually happened still passed. --- src/TaggableCachePoolTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TaggableCachePoolTest.php b/src/TaggableCachePoolTest.php index c275239..7bad680 100644 --- a/src/TaggableCachePoolTest.php +++ b/src/TaggableCachePoolTest.php @@ -221,7 +221,7 @@ public function testRemoveTagWhenItemIsRemoved() // Save the item and then delete it $this->cache->save($item); - $this->cache->deleteItem('key'); + $this->assertTrue($this->cache->deleteItem('key'), 'deleteItem() must return true when a tagged item is deleted'); // Create a new item (same key) (no tags) $item = $this->cache->getItem('key')->set('value');