/
githubmirror
/
framework
Обзор
Документация
Войти
/
githubmirror
/
framework
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
13.x
tests/Cache/CacheRepositoryTest.php
848 строк
29 KB
Jason McCreary
[13.x] Mockery cleanup (#61117)
10 авг 2026, 20:23
Не верифицирован
10 авг 2026, 20:23
2ee40ee
Код
Авторство
О чём код?
<?php namespace Illuminate\Tests\Cache; use ArrayIterator; use BadMethodCallException; use DateInterval; use DateTime; use DateTimeImmutable; use Illuminate\Cache\ArrayStore; use Illuminate\Cache\FileStore; use Illuminate\Cache\Lock; use Illuminate\Cache\MemcachedStore; use Illuminate\Cache\RedisStore; use Illuminate\Cache\Repository; use Illuminate\Cache\TaggableStore; use Illuminate\Cache\TaggedCache; use Illuminate\Container\Container; use Illuminate\Contracts\Cache\LockProvider; use Illuminate\Contracts\Cache\LockTimeoutException; use Illuminate\Contracts\Cache\Store; use Illuminate\Events\Dispatcher; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Carbon; use InvalidArgumentException; use Mockery; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use stdClass; class CacheRepositoryTest extends TestCase { protected function setUp(): void { Carbon::setTestNow(Carbon::parse(self::getTestDate())); } protected function tearDown(): void { Repository::handleUnserializableClassUsing(null); } public function testGetReturnsValueFromCache() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $this->assertSame('bar', $repo->get('foo')); } public function testGetReturnsMultipleValuesFromCacheWhenGivenAnArray() { $repo = $this->getRepository(); $repo->getStore()->expects('many')->with(['foo', 'bar'])->andReturn(['foo' => 'bar', 'bar' => 'baz']); $this->assertEquals(['foo' => 'bar', 'bar' => 'baz'], $repo->get(['foo', 'bar'])); } public function testGetReturnsMultipleValuesFromCacheWhenGivenAnArrayWithDefaultValues() { $repo = $this->getRepository(); $repo->getStore()->expects('many')->with(['foo', 'bar'])->andReturn(['foo' => null, 'bar' => 'baz']); $this->assertEquals(['foo' => 'default', 'bar' => 'baz'], $repo->get(['foo' => 'default', 'bar'])); } public function testGetReturnsMultipleValuesFromCacheWhenGivenAnArrayOfOneTwoThree() { $repo = $this->getRepository(); $repo->getStore()->expects('many')->with([1, 2, 3])->andReturn([1 => null, 2 => null, 3 => null]); $this->assertEquals([1 => null, 2 => null, 3 => null], $repo->get([1, 2, 3])); } public function testDefaultValueIsReturned() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->times(2)->andReturn(null); $this->assertSame('bar', $repo->get('foo', 'bar')); $this->assertSame('baz', $repo->get('boom', function () { return 'baz'; })); } public function testSettingDefaultCacheTime() { $repo = $this->getRepository(); $repo->setDefaultCacheTime(10); $this->assertEquals(10, $repo->getDefaultCacheTime()); } public function testHasMethod() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $repo->getStore()->expects('get')->with('bar')->andReturn('bar'); $repo->getStore()->expects('get')->with('baz')->andReturn(false); $this->assertTrue($repo->has('bar')); $this->assertFalse($repo->has('foo')); $this->assertTrue($repo->has('baz')); } public function testMissingMethod() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $repo->getStore()->expects('get')->with('bar')->andReturn('bar'); $this->assertTrue($repo->missing('foo')); $this->assertFalse($repo->missing('bar')); } public function testRememberMethodCallsPutAndReturnsDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->andReturn(null); $repo->getStore()->expects('put')->with('foo', 'bar', 10); $result = $repo->remember('foo', 10, function () { return 'bar'; }); $this->assertSame('bar', $result); $repo = $this->getRepository(); $repo->getStore()->expects('get')->times(2)->andReturn(null); $repo->getStore()->expects('put')->with('foo', 'bar', 602); $repo->getStore()->expects('put')->with('baz', 'qux', 598); $result = $repo->remember('foo', Carbon::now()->addMinutes(10)->addSeconds(2), function () { return 'bar'; }); $this->assertSame('bar', $result); $result = $repo->remember('baz', Carbon::now()->addMinutes(10)->subSeconds(2), function () { return 'qux'; }); $this->assertSame('qux', $result); // Use a callable... $repo = $this->getRepository(); $repo->getStore()->expects('get')->andReturn(null); $repo->getStore()->expects('put')->with('foo', 'bar', 10); $result = $repo->remember('foo', function () { return 10; }, function () { return 'bar'; }); $this->assertSame('bar', $result); } public function testRememberWithWarmthReturnsCachedValue() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $repo->getStore()->shouldReceive('put')->never(); $result = $repo->rememberWithWarmth('foo', 10, function () { $this->fail('The cache callback should not be called.'); }); $this->assertSame(['bar', true], $result); } public function testRememberWithWarmthCallsPutAndReturnsDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $repo->getStore()->expects('put')->with('foo', 'bar', 10); $result = $repo->rememberWithWarmth('foo', function ($value) { $this->assertSame('bar', $value); return 10; }, function () { return 'bar'; }); $this->assertSame(['bar', false], $result); } public function testRememberForeverMethodCallsForeverAndReturnsDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->andReturn(null); $repo->getStore()->expects('forever')->with('foo', 'bar'); $result = $repo->rememberForever('foo', function () { return 'bar'; }); $this->assertSame('bar', $result); } public function testPuttingMultipleItemsInCache() { $repo = $this->getRepository(); $repo->getStore()->expects('putMany')->with(['foo' => 'bar', 'bar' => 'baz'], 1); $repo->put(['foo' => 'bar', 'bar' => 'baz'], 1); } public function testSettingMultipleItemsInCacheArray() { $repo = $this->getRepository(); $repo->getStore()->expects('putMany')->with(['foo' => 'bar', 'bar' => 'baz'], 1)->andReturn(true); $result = $repo->setMultiple(['foo' => 'bar', 'bar' => 'baz'], 1); $this->assertTrue($result); } public function testSettingMultipleItemsInCacheIterator() { $repo = $this->getRepository(); $repo->getStore()->expects('putMany')->with(['foo' => 'bar', 'bar' => 'baz'], 1)->andReturn(true); $result = $repo->setMultiple(new ArrayIterator(['foo' => 'bar', 'bar' => 'baz']), 1); $this->assertTrue($result); } public function testPutWithNullTTLRemembersItemForever() { $repo = $this->getRepository(); $repo->getStore()->expects('forever')->with('foo', 'bar')->andReturn(true); $this->assertTrue($repo->put('foo', 'bar')); } public function testPutWithDatetimeInPastOrZeroSecondsRemovesOldItem() { $repo = $this->getRepository(); $repo->getStore()->shouldReceive('put')->never(); $repo->getStore()->expects('forget')->times(2)->andReturn(true); $result = $repo->put('foo', 'bar', Carbon::now()->subMinutes(10)); $this->assertTrue($result); $result = $repo->put('foo', 'bar', Carbon::now()); $this->assertTrue($result); } public function testPutManyWithNullTTLRemembersItemsForever() { $repo = $this->getRepository(); $repo->getStore()->expects('forever')->with('foo', 'bar')->andReturn(true); $repo->getStore()->expects('forever')->with('bar', 'baz')->andReturn(true); $this->assertTrue($repo->putMany(['foo' => 'bar', 'bar' => 'baz'])); } public function testAddWithStoreFailureReturnsFalse() { $repo = $this->getRepository(); $repo->getStore()->shouldReceive('add')->never(); $repo->getStore()->expects('get')->andReturn(null); $repo->getStore()->expects('put')->andReturn(false); $this->assertFalse($repo->add('foo', 'bar', 60)); } public function testCacheAddCallsRedisStoreAdd() { $store = Mockery::mock(RedisStore::class); $store->expects('add')->with('k', 'v', 60)->andReturn(true); $repository = new Repository($store); $this->assertTrue($repository->add('k', 'v', 60)); } public function testAddMethodCanAcceptDateIntervals() { $storeWithAdd = Mockery::mock(RedisStore::class); $storeWithAdd->expects('add')->with('k', 'v', 61)->andReturn(true); $repository = new Repository($storeWithAdd); $this->assertTrue($repository->add('k', 'v', DateInterval::createFromDateString('61 seconds'))); $storeWithoutAdd = Mockery::mock(ArrayStore::class); $this->assertFalse(method_exists(ArrayStore::class, 'add'), 'This store should not have add method on it.'); $storeWithoutAdd->expects('get')->with('k')->andReturn(null); $storeWithoutAdd->expects('put')->with('k', 'v', 60)->andReturn(true); $repository = new Repository($storeWithoutAdd); $this->assertTrue($repository->add('k', 'v', DateInterval::createFromDateString('60 seconds'))); } public function testAddMethodCanAcceptDateTimeInterface() { $withAddStore = Mockery::mock(RedisStore::class); $withAddStore->expects('add')->with('k', 'v', 61)->andReturn(true); $repository = new Repository($withAddStore); $this->assertTrue($repository->add('k', 'v', Carbon::now()->addSeconds(61))); $noAddStore = Mockery::mock(ArrayStore::class); $this->assertFalse(method_exists(ArrayStore::class, 'add'), 'This store should not have add method on it.'); $noAddStore->expects('get')->with('k')->andReturn(null); $noAddStore->expects('put')->with('k', 'v', 62)->andReturn(true); $repository = new Repository($noAddStore); $this->assertTrue($repository->add('k', 'v', Carbon::now()->addSeconds(62))); } public function testAddWithNullTTLRemembersItemForever() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $repo->getStore()->expects('forever')->with('foo', 'bar')->andReturn(true); $this->assertTrue($repo->add('foo', 'bar')); } public function testAddWithDatetimeInPastOrZeroSecondsReturnsImmediately() { $repo = $this->getRepository(); $repo->getStore()->shouldReceive('add', 'get', 'put')->never(); $result = $repo->add('foo', 'bar', Carbon::now()->subMinutes(10)); $this->assertFalse($result); $result = $repo->add('foo', 'bar', Carbon::now()); $this->assertFalse($result); $result = $repo->add('foo', 'bar', -1); $this->assertFalse($result); } public static function dataProviderTestGetSeconds() { return [ [Carbon::parse(self::getTestDate())->addMinutes(5)], [(new DateTime(self::getTestDate()))->modify('+5 minutes')], [(new DateTimeImmutable(self::getTestDate()))->modify('+5 minutes')], [new DateInterval('PT5M')], [300], ]; } /** * @param mixed $duration */ #[DataProvider('dataProviderTestGetSeconds')] public function testGetSeconds($duration) { $repo = $this->getRepository(); $repo->getStore()->expects('put')->with($key = 'foo', $value = 'bar', 300); $repo->put($key, $value, $duration); } public function testRegisterMacroWithNonStaticCall() { $repo = $this->getRepository(); $repo::macro(__CLASS__, function () { return 'Taylor'; }); $this->assertSame('Taylor', $repo->{__CLASS__}()); } public function testForgettingCacheKey() { $repo = $this->getRepository(); $repo->getStore()->expects('forget')->with('a-key')->andReturn(true); $repo->forget('a-key'); } public function testRemovingCacheKey() { // Alias of Forget $repo = $this->getRepository(); $repo->getStore()->expects('forget')->with('a-key')->andReturn(true); $repo->delete('a-key'); } public function testSettingCache() { $repo = $this->getRepository(); $repo->getStore()->expects('put')->with($key = 'foo', $value = 'bar', 1)->andReturn(true); $result = $repo->set($key, $value, 1); $this->assertTrue($result); } public function testClearingWholeCache() { $repo = $this->getRepository(); $repo->getStore()->expects('flush')->andReturn(true); $repo->clear(); } public function testGettingMultipleValuesFromCache() { $keys = ['key1', 'key2', 'key3']; $default = 5; $repo = $this->getRepository(); $repo->getStore()->expects('many')->with(['key1', 'key2', 'key3'])->andReturn(['key1' => 1, 'key2' => null, 'key3' => null]); $this->assertEquals(['key1' => 1, 'key2' => 5, 'key3' => 5], $repo->getMultiple($keys, $default)); } public function testRemovingMultipleKeys() { $repo = $this->getRepository(); $repo->getStore()->expects('forget')->with('a-key')->andReturn(true); $repo->getStore()->expects('forget')->with('a-second-key')->andReturn(true); $this->assertTrue($repo->deleteMultiple(['a-key', 'a-second-key'])); } public function testRemovingMultipleKeysFailsIfOneFails() { $repo = $this->getRepository(); $repo->getStore()->expects('forget')->with('a-key')->andReturn(true); $repo->getStore()->expects('forget')->with('a-second-key')->andReturn(false); $this->assertFalse($repo->deleteMultiple(['a-key', 'a-second-key'])); } public function testAllTagsArePassedToTaggableStore() { $store = Mockery::mock(ArrayStore::class); $repo = new Repository($store); $taggedCache = Mockery::mock(); $taggedCache->expects('setDefaultCacheTime'); $store->expects('tags')->with(['foo', 'bar', 'baz'])->andReturn($taggedCache); $repo->tags('foo', 'bar', 'baz'); } public function testItThrowsExceptionWhenStoreDoesNotSupportTags() { $this->expectException(BadMethodCallException::class); $store = new FileStore(new Filesystem, '/usr'); $this->assertFalse(method_exists($store, 'tags'), 'Store should not support tagging.'); (new Repository($store))->tags('foo'); } public function testTagMethodReturnsTaggedCache() { $store = (new Repository(new ArrayStore()))->tags('foo'); $this->assertInstanceOf(TaggedCache::class, $store); } public function testPossibleInputTypesToTags() { $repo = new Repository(new ArrayStore()); $store = $repo->tags('foo'); $this->assertEquals(['foo'], $store->getTags()->getNames()); $store = $repo->tags(['foo!', 'Kangaroo']); $this->assertEquals(['foo!', 'Kangaroo'], $store->getTags()->getNames()); $store = $repo->tags('r1', 'r2', 'r3'); $this->assertEquals(['r1', 'r2', 'r3'], $store->getTags()->getNames()); } public function testEventDispatcherIsPassedToStoreFromRepository() { $repo = new Repository(new ArrayStore()); $repo->setEventDispatcher(new Dispatcher()); $store = $repo->tags('foo'); $this->assertSame($store->getEventDispatcher(), $repo->getEventDispatcher()); } public function testDefaultCacheLifeTimeIsSetOnTaggableStore() { $repo = new Repository(new ArrayStore()); $repo->setDefaultCacheTime(random_int(1, 100)); $store = $repo->tags('foo'); $this->assertSame($store->getDefaultCacheTime(), $repo->getDefaultCacheTime()); } public function testFlushLocksDelegatesToStore() { $flushable = Mockery::mock(RedisStore::class); $flushable->expects('flushLocks')->andReturn(true); $repo = new Repository($flushable); $this->assertTrue($repo->flushLocks()); } public function testTaggableRepositoriesSupportTags() { $taggable = Mockery::mock(TaggableStore::class); $taggableRepo = new Repository($taggable); $this->assertTrue($taggableRepo->supportsTags()); } public function testNonTaggableRepositoryDoesNotSupportTags() { $nonTaggable = Mockery::mock(FileStore::class); $nonTaggableRepo = new Repository($nonTaggable); $this->assertFalse($nonTaggableRepo->supportsTags()); } public function testFlushableLockRepositorySupportsFlushingLocks() { $flushable = Mockery::mock(RedisStore::class); $flushableRepo = new Repository($flushable); $this->assertTrue($flushableRepo->supportsFlushingLocks()); } public function testNonFlushableLockRepositoryDoesNotSupportFlushingLocks() { $nonFlushable = Mockery::mock(MemcachedStore::class); $nonFlushableRepo = new Repository($nonFlushable); $this->assertFalse($nonFlushableRepo->supportsFlushingLocks()); } public function testItThrowsExceptionWhenStoreDoesNotSupportFlushingLocks() { $this->expectException(BadMethodCallException::class); $nonFlushable = Mockery::mock(MemcachedStore::class); $nonFlushableRepo = new Repository($nonFlushable); $nonFlushableRepo->flushLocks(); } public function testTouchWithSecondsTtlCorrectlyProxiesToStore(): void { $key = 'key'; $ttl = 60; $repo = $this->getRepository(); $repo->getStore()->expects('touch')->with($key, $ttl)->andReturn(true); $this->assertTrue($repo->touch($key, $ttl)); } public function testTouchWithDatetimeTtlCorrectlyProxiesToStore(): void { $key = 'key'; $ttl = 60; Carbon::setTestNow($now = Carbon::now()); $repo = $this->getRepository(); $repo->getStore()->expects('touch')->with($key, $ttl)->andReturn(true); $this->assertTrue($repo->touch($key, $now->addSeconds($ttl))); } public function testTouchWithDateIntervalTtlCorrectlyProxiesToStore(): void { $key = 'key'; $ttl = 60; $repo = $this->getRepository(); $repo->getStore()->expects('touch')->with($key, $ttl)->andReturn(true); $this->assertTrue($repo->touch($key, DateInterval::createFromDateString("$ttl seconds"))); } public function testTouchWithDatetimeInPastOrZeroSecondsRemovesOldItem(): void { $repo = $this->getRepository(); $repo->getStore()->shouldReceive('touch')->never(); $repo->getStore()->expects('forget')->times(2)->with('key')->andReturn(true); $this->assertTrue($repo->touch('key', Carbon::now()->subMinute())); $this->assertTrue($repo->touch('key', 0)); } public function testTouchWorksWithEnumKey(): void { $ttl = 60; $repo = $this->getRepository(); $repo->getStore()->expects('touch')->with('foo', $ttl)->andReturn(true); $this->assertTrue($repo->touch(TestCacheKey::FOO, $ttl)); } public function testAtomicExecutesCallbackAndReturnsResult() { $repo = new Repository(new ArrayStore); $result = $repo->withoutOverlapping('foo', function () { return 'bar'; }); $this->assertSame('bar', $result); } public function testAtomicPassesLockAndWaitSecondsToLock() { $store = Mockery::mock(Store::class, LockProvider::class); $repo = new Repository($store); $lock = Mockery::mock(Lock::class); $store->expects('lock')->with('foo', 30, null)->andReturn($lock); $lock->expects('block')->with(15, Mockery::type('callable'))->andReturnUsing(function ($seconds, $callback) { return $callback(); }); $result = $repo->withoutOverlapping('foo', function () { return 'bar'; }, 30, 15); $this->assertSame('bar', $result); } public function testAtomicPassesOwnerToLock() { $store = Mockery::mock(Store::class, LockProvider::class); $repo = new Repository($store); $lock = Mockery::mock(Lock::class); $store->expects('lock')->with('foo', 10, 'my-owner')->andReturn($lock); $lock->expects('block')->with(10, Mockery::type('callable'))->andReturnUsing(function ($seconds, $callback) { return $callback(); }); $result = $repo->withoutOverlapping('foo', function () { return 'bar'; }, 10, 10, 'my-owner'); $this->assertSame('bar', $result); } public function testAtomicThrowsOnLockTimeout() { $repo = new Repository(new ArrayStore); $repo->getStore()->lock('foo', 10)->acquire(); $called = false; try { $repo->withoutOverlapping('foo', function () use (&$called) { $called = true; }, 10, 0); $this->fail('Expected LockTimeoutException was not thrown.'); } catch (LockTimeoutException) { $this->assertFalse($called); } } public function testTaggedCacheWorksWithEnumKey() { $cache = (new Repository(new ArrayStore()))->tags('test-tag'); $cache->put(TestCacheKey::FOO, 5); $this->assertSame(6, $cache->increment(TestCacheKey::FOO)); $this->assertSame(5, $cache->decrement(TestCacheKey::FOO)); } public function testGetReturnsIncompleteClassWhenNoHandlerRegistered() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(unserialize(serialize(new stdClass), ['allowed_classes' => false])); $this->assertInstanceOf(\__PHP_Incomplete_Class::class, $repo->get('foo')); } public function testGetCallsHandlerWithKeyAndClassForIncompleteClass() { $class = null; $key = null; Repository::handleUnserializableClassUsing(function ($k, $c) use (&$class, &$key) { $key = $k; $class = $c; }); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(unserialize(serialize(new stdClass), ['allowed_classes' => false])); $repo->get('foo'); $this->assertSame('foo', $key); $this->assertSame('stdClass', $class); } public function testManyCallsHandlerForEachIncompleteClass() { $handled = []; Repository::handleUnserializableClassUsing(function ($key, $class) use (&$handled) { $handled[] = $key; }); $repo = $this->getRepository(); $repo->getStore()->expects('many')->with(['foo', 'bar'])->andReturn(['foo' => unserialize(serialize(new stdClass), ['allowed_classes' => false]), 'bar' => 'baz']); $repo->many(['foo', 'bar']); $this->assertSame(['foo'], $handled); } protected function getRepository() { $dispatcher = new Dispatcher(Mockery::mock(Container::class)); $repository = new Repository(Mockery::mock(Store::class)); $repository->setEventDispatcher($dispatcher); return $repository; } protected static function getTestDate() { return '2030-07-25 12:13:14 UTC'; } public function testItGetsAsString() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $this->assertSame('bar', $repo->string('foo')); } public function testItGetsAsStringWithDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $this->assertSame('default', $repo->string('foo', 'default')); } public function testItThrowsExceptionWhenGettingNonStringAsString() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be a string, integer given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(123); $repo->string('foo'); } public function testItGetsAsInteger() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(123); $this->assertSame(123, $repo->integer('foo')); } public function testItGetsAsIntegerWithDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $this->assertSame(456, $repo->integer('foo', 456)); } public function testItGetsAsIntegerFromNumericString() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('123'); $this->assertSame(123, $repo->integer('foo')); } public function testItThrowsExceptionWhenGettingNonIntegerAsInteger() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be an integer, string given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $repo->integer('foo'); } public function testItThrowsExceptionWhenGettingFloatStringAsInteger() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be an integer, string given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('1.5'); $repo->integer('foo'); } public function testItGetsAsFloat() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(1.5); $this->assertSame(1.5, $repo->float('foo')); } public function testItGetsAsFloatWithDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $this->assertSame(2.5, $repo->float('foo', 2.5)); } public function testItGetsAsFloatFromNumericString() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('1.5'); $this->assertSame(1.5, $repo->float('foo')); } public function testItThrowsExceptionWhenGettingNonFloatAsFloat() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be a float, string given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $repo->float('foo'); } public function testItGetsAsBoolean() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(true); $this->assertTrue($repo->boolean('foo')); } public function testItGetsAsBooleanWithDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $this->assertFalse($repo->boolean('foo', false)); } public function testItThrowsExceptionWhenGettingNonBooleanAsBoolean() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be a boolean, string given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $repo->boolean('foo'); } public function testItGetsAsArray() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(['bar', 'baz']); $this->assertSame(['bar', 'baz'], $repo->array('foo')); } public function testItGetsAsArrayWithDefault() { $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn(null); $this->assertSame(['default'], $repo->array('foo', ['default'])); } public function testItThrowsExceptionWhenGettingNonArrayAsArray() { $this->expectExceptionObject(new InvalidArgumentException('Cache value for key [foo] must be an array, string given.')); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn('bar'); $repo->array('foo'); } public static function typedGetterTypeMismatchProvider() { return [ ['string', 123, 'Cache value for key [foo] must be a string, integer given.'], ['integer', 'bar', 'Cache value for key [foo] must be an integer, string given.'], ['float', 'bar', 'Cache value for key [foo] must be a float, string given.'], ['boolean', 'bar', 'Cache value for key [foo] must be a boolean, string given.'], ['array', 'bar', 'Cache value for key [foo] must be an array, string given.'], ]; } #[DataProvider('typedGetterTypeMismatchProvider')] public function testTypedGettersReportTypeMismatchesForEnumKeys($method, $value, $message) { $this->expectExceptionObject(new InvalidArgumentException($message)); $repo = $this->getRepository(); $repo->getStore()->expects('get')->with('foo')->andReturn($value); $repo->{$method}(TestCacheKey::FOO); } } enum TestCacheKey: string { case FOO = 'foo'; }