cache = new ArrayCache(); } public function testCanSetAndGetValue(): void { $setResult = $this->cache->set('key1', 'value1'); self::assertSame('value1', $this->cache->get('key1')); self::assertTrue($setResult); } public function testReturnsDefaultWhenKeyNotExists(): void { self::assertNull($this->cache->get('nonexistent')); self::assertSame('default', $this->cache->get('nonexistent', 'default')); } public function testReturnsExistsStateForCacheKeys(): void { $this->cache->set('key1', 'value1'); self::assertTrue($this->cache->has('key1')); self::assertFalse($this->cache->has('nonexistent')); } public function testCanDeleteAKey(): void { $this->cache->set('key1', 'value1'); self::assertTrue($this->cache->has('key1')); $deleteResult = $this->cache->delete('key1'); self::assertFalse($this->cache->has('key1')); self::assertTrue($deleteResult); } public function testReturnsTrueForDeletionEvenForNonExistentKey(): void { $result = $this->cache->delete('nonexistent'); self::assertTrue($result); } public function testCanClearAllKeys(): void { $this->cache->set('key1', 'value1'); $this->cache->set('key2', 'value2'); $this->cache->clear(); self::assertFalse($this->cache->has('key1')); self::assertFalse($this->cache->has('key2')); } public function testConsidersTtlForCacheItemsWithIntegers(): void { $this->cache->set('key1', 'value1', 1); self::assertTrue($this->cache->has('key1')); self::assertSame('value1', $this->cache->get('key1')); // Sleep to let TTL expire sleep(2); self::assertFalse($this->cache->has('key1')); self::assertNull($this->cache->get('key1')); } public function testConsidersTtlForCacheItemsWithDateIntervals(): void { $interval = new DateInterval('PT1S'); // 1 second $this->cache->set('key1', 'value1', $interval); self::assertTrue($this->cache->has('key1')); self::assertSame('value1', $this->cache->get('key1')); // Sleep to let TTL expire sleep(2); self::assertFalse($this->cache->has('key1')); self::assertNull($this->cache->get('key1')); } public function testReturnsArrayIfMultipleItemsAreRequested(): void { $this->cache->set('key1', 'value1'); $this->cache->set('key2', 'value2'); $result = $this->cache->getMultiple(['key1', 'key2', 'key3'], 'default'); self::assertSame( [ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'default', ], $result, ); } public function testCanSetMultipleItems(): void { $values = [ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ]; $result = $this->cache->setMultiple($values); self::assertTrue($result); self::assertSame('value1', $this->cache->get('key1')); self::assertSame('value2', $this->cache->get('key2')); self::assertSame('value3', $this->cache->get('key3')); } public function testCanSetMultipleItemsWithTtl(): void { $values = [ 'key1' => 'value1', 'key2' => 'value2', ]; $this->cache->setMultiple($values, 1); self::assertTrue($this->cache->has('key1')); self::assertTrue($this->cache->has('key2')); sleep(2); self::assertFalse($this->cache->has('key1')); self::assertFalse($this->cache->has('key2')); } public function testCanDeleteMultipleItemsByKey(): void { $this->cache->set('key1', 'value1'); $this->cache->set('key2', 'value2'); $this->cache->set('key3', 'value3'); $result = $this->cache->deleteMultiple(['key1', 'key3']); self::assertTrue($result); self::assertFalse($this->cache->has('key1')); self::assertTrue($this->cache->has('key2')); self::assertFalse($this->cache->has('key3')); } public function testCanStoreComplexDataTypes(): void { $array = ['nested' => ['data' => 'value']]; $object = new stdClass(); $object->property = 'test'; $this->cache->set('array', $array); $this->cache->set('object', $object); self::assertSame($array, $this->cache->get('array')); self::assertEquals($object, $this->cache->get('object')); } public function testThrowsExceptionOnInvalidKeys(): void { $this->expectException(InvalidArgumentException::class); $this->cache->set('invalid{key}', 'value'); } public function testThrowsExceptionOnEmptyKeys(): void { $this->expectException(InvalidArgumentException::class); $this->cache->set('', 'value'); } public function testThrowsExceptionOnKeysWithInvalidCharacters(): void { $invalidKeys = ['key{', 'key}', 'key(', 'key)', 'key/', 'key\\', 'key@', 'key:']; foreach ($invalidKeys as $key) { try { $this->cache->set($key, 'value'); self::fail("Expected InvalidArgumentException for key: $key"); } catch (InvalidArgumentException $e) { // Expected exception self::assertTrue(true); } } } public function testExpiredKeysAreRemovedOnAccess(): void { $this->cache->set('key1', 'value1', 1); // Verify it exists initially self::assertTrue($this->cache->has('key1')); // Wait for expiry sleep(2); // Access should trigger cleanup self::assertFalse($this->cache->has('key1')); self::assertNull($this->cache->get('key1')); } }