diff --git a/composer.json b/composer.json index f223b78..874f5fb 100755 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "php": ">=5.5.9" }, "require-dev": { + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "cache/cache": "^1.0", "symfony/cache": "^3.4.31|^4.3.4|^5.0", "symfony/phpunit-bridge": "^5.1,<5.3", diff --git a/src/CachePoolTest.php b/src/CachePoolTest.php index d91b8f9..c57c914 100644 --- a/src/CachePoolTest.php +++ b/src/CachePoolTest.php @@ -1,5 +1,7 @@ fail('Expected exception to be thrown.'); + } catch (\TypeError $e) { + $this->assertTrue(true); + } catch (\Psr\Cache\InvalidArgumentException $e) { + $this->assertTrue(true); + } + } + /** * Data provider for invalid keys. * @@ -360,9 +380,9 @@ public function testSaveExpired() $item = $this->cache->getItem('key'); $item->set('value'); - $item->expiresAt(\DateTime::createFromFormat('U', time() + 10)); + $item->expiresAt(\DateTime::createFromFormat('U', (string) (time() + 10))); $this->cache->save($item); - $item->expiresAt(\DateTime::createFromFormat('U', time() - 1)); + $item->expiresAt(\DateTime::createFromFormat('U', (string) (time() - 1))); $this->cache->save($item); $item = $this->cache->getItem('key'); $this->assertFalse($item->isHit(), 'Cache should not save expired items'); @@ -421,7 +441,7 @@ public function testDeferredExpired() $item = $this->cache->getItem('key'); $item->set('4711'); - $item->expiresAt(\DateTime::createFromFormat('U', time() - 1)); + $item->expiresAt(\DateTime::createFromFormat('U', (string) (time() - 1))); $this->cache->saveDeferred($item); $this->assertFalse($this->cache->hasItem('key'), 'Cache should not have expired deferred item'); @@ -581,8 +601,9 @@ public function testGetItemInvalidKeys($key) $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\Cache\InvalidArgumentException'); - $this->cache->getItem($key); + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->getItem($key); + }); } /** @@ -609,8 +630,9 @@ public function testHasItemInvalidKeys($key) $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\Cache\InvalidArgumentException'); - $this->cache->hasItem($key); + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->hasItem($key); + }); } /** @@ -623,8 +645,9 @@ public function testDeleteItemInvalidKeys($key) $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\Cache\InvalidArgumentException'); - $this->cache->deleteItem($key); + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->deleteItem($key); + }); } /** diff --git a/src/SimpleCacheTest.php b/src/SimpleCacheTest.php index 0165b26..91c5128 100644 --- a/src/SimpleCacheTest.php +++ b/src/SimpleCacheTest.php @@ -1,5 +1,7 @@ 'v'). + * + * @return array + */ + public static function invalidArrayKeysTypeViolation() + { + return [ + [true], + [false], + [null], + [2.5], [new \stdClass()], [['array']], ]; } /** + * Data provider for invalid TTL values. + * + * These are values that survive PHP's null|int|\DateInterval type hint + * but are still invalid per the PSR-16 spec. + * * @return array */ public static function invalidTtl() { return [ [''], - [true], - [false], ['abc'], - [2.5], - [' 1'], // can be casted to a int - ['12foo'], // can be casted to a int - ['025'], // can be interpreted as hex [new \stdClass()], [['array']], ]; } + /** + * Data provider for TTL values whose *type* violates the interface contract. + * + * @return array + */ + public static function invalidTtlTypeViolation() + { + return [ + [true], + [false], + [2.5], + [' 1'], + ['12foo'], + ['025'], + ]; + } + + /** + * Accepts either \Psr\SimpleCache\InvalidArgumentException (library-level) or + * \TypeError (PHP-level contract violation) as a valid failure. + * + * @param callable(): void $callable + */ + private function assertCacheExceptionOrTypeError(callable $callable): void + { + try { + $callable(); + $this->fail('Expected exception to be thrown.'); + } catch (\TypeError $e) { + $this->assertTrue(true); + } catch (\Psr\SimpleCache\InvalidArgumentException $e) { + $this->assertTrue(true); + } + } + /** * Data provider for valid keys. * @@ -460,6 +545,21 @@ public function testGetInvalidKeys($key) $this->cache->get($key); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testGetInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->get($key); + }); + } + /** * @dataProvider invalidKeys */ @@ -474,14 +574,30 @@ public function testGetMultipleInvalidKeys($key) $result = $this->cache->getMultiple(['key1', $key, 'key2']); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testGetMultipleInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->getMultiple(['key1', $key, 'key2']); + }); + } + public function testGetMultipleNoIterable() { if (isset($this->skippedTests[__FUNCTION__])) { $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\SimpleCache\InvalidArgumentException'); - $result = $this->cache->getMultiple('key'); + $this->assertCacheExceptionOrTypeError(function () { + $this->cache->getMultiple('key'); + }); } /** @@ -498,6 +614,21 @@ public function testSetInvalidKeys($key) $this->cache->set($key, 'foobar'); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testSetInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->set($key, 'foobar'); + }); + } + /** * @dataProvider invalidArrayKeys */ @@ -517,14 +648,35 @@ public function testSetMultipleInvalidKeys($key) $this->cache->setMultiple($values()); } + /** + * @dataProvider invalidArrayKeysTypeViolation + */ + #[DataProvider('invalidArrayKeysTypeViolation')] + public function testSetMultipleInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $values = function () use ($key) { + yield 'key1' => 'foo'; + yield $key => 'bar'; + yield 'key2' => 'baz'; + }; + $this->cache->setMultiple($values()); + }); + } + public function testSetMultipleNoIterable() { if (isset($this->skippedTests[__FUNCTION__])) { $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\SimpleCache\InvalidArgumentException'); - $this->cache->setMultiple('key'); + $this->assertCacheExceptionOrTypeError(function () { + $this->cache->setMultiple('key'); + }); } /** @@ -541,6 +693,21 @@ public function testHasInvalidKeys($key) $this->cache->has($key); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testHasInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->has($key); + }); + } + /** * @dataProvider invalidKeys */ @@ -555,6 +722,21 @@ public function testDeleteInvalidKeys($key) $this->cache->delete($key); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testDeleteInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->delete($key); + }); + } + /** * @dataProvider invalidKeys */ @@ -569,14 +751,30 @@ public function testDeleteMultipleInvalidKeys($key) $this->cache->deleteMultiple(['key1', $key, 'key2']); } + /** + * @dataProvider invalidKeysTypeViolation + */ + #[DataProvider('invalidKeysTypeViolation')] + public function testDeleteMultipleInvalidKeysTypeViolation($key) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($key) { + $this->cache->deleteMultiple(['key1', $key, 'key2']); + }); + } + public function testDeleteMultipleNoIterable() { if (isset($this->skippedTests[__FUNCTION__])) { $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\SimpleCache\InvalidArgumentException'); - $this->cache->deleteMultiple('key'); + $this->assertCacheExceptionOrTypeError(function () { + $this->cache->deleteMultiple('key'); + }); } /** @@ -589,8 +787,24 @@ public function testSetInvalidTtl($ttl) $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\SimpleCache\InvalidArgumentException'); - $this->cache->set('key', 'value', $ttl); + $this->assertCacheExceptionOrTypeError(function () use ($ttl) { + $this->cache->set('key', 'value', $ttl); + }); + } + + /** + * @dataProvider invalidTtlTypeViolation + */ + #[DataProvider('invalidTtlTypeViolation')] + public function testSetInvalidTtlTypeViolation($ttl) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($ttl) { + $this->cache->set('key', 'value', $ttl); + }); } /** @@ -603,8 +817,24 @@ public function testSetMultipleInvalidTtl($ttl) $this->markTestSkipped($this->skippedTests[__FUNCTION__]); } - $this->expectException('Psr\SimpleCache\InvalidArgumentException'); - $this->cache->setMultiple(['key' => 'value'], $ttl); + $this->assertCacheExceptionOrTypeError(function () use ($ttl) { + $this->cache->setMultiple(['key' => 'value'], $ttl); + }); + } + + /** + * @dataProvider invalidTtlTypeViolation + */ + #[DataProvider('invalidTtlTypeViolation')] + public function testSetMultipleInvalidTtlTypeViolation($ttl) + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $this->assertCacheExceptionOrTypeError(function () use ($ttl) { + $this->cache->setMultiple(['key' => 'value'], $ttl); + }); } public function testNullOverwrite()