true, 'verboseOutput' => true ]); $base = sys_get_temp_dir().'/lbcache_'.bin2hex(random_bytes(6)); $test->describe('キャッシュ', function($test) use ($base): void { $test->it('保存して受け取れるはず(ディレクトリも作るはず)', function($test) use ($base): void { $cache = new Cache('test', $base); $res = $cache->set('domainlist', ['a' => 1, 'b' => ['日本語']]); $test->assertTrue($res->isSuccess); $test->assertTrue(is_file("{$base}/test/domainlist.json")); $data = $cache->get('domainlist'); $test->assertEquals(1, $data['a']); $test->assertEquals(['日本語'], $data['b']); $test->assertTrue(is_int($data['lifespan'])); }); $test->it('無いキャッシュは空の配列のはず', function($test) use ($base): void { $test->assertEquals([], (new Cache('test', $base))->get('nothing')); $test->assertEquals([], (new Cache('nodir', $base))->get('x')); }); $test->it('壊れたJSONは空の配列のはず', function($test) use ($base): void { file_put_contents("{$base}/test/broken.json", '{"a":'); $test->assertEquals([], (new Cache('test', $base))->get('broken')); }); $test->it('有効期限を確認出来るはず', function($test) use ($base): void { $cache = new Cache('test', $base); $cache->set('q', ['query' => ['page' => 1]]); $data = $cache->get('q'); $test->assertTrue($cache->resurrect($data)); $test->assertTrue($cache->resurrect($data, ['page' => 1])); $test->assertFalse($cache->resurrect($data, ['page' => 2])); $test->assertFalse($cache->resurrect([])); $expired = $data; $expired['lifespan'] = time() - 3600; $test->assertFalse($cache->resurrect($expired)); // 有効期限を変えられる(protected) $short = new class('test', $base) extends Cache { protected int $dataDuration = 0; }; $test->assertFalse($short->resurrect($data)); }); $test->it('削除出来るはず', function($test) use ($base): void { $cache = new Cache('test', $base); $test->assertTrue($cache->murder('domainlist')->isSuccess); $test->assertEquals([], $cache->get('domainlist')); $test->assertFalse($cache->murder('domainlist')->isSuccess); }); $test->it('名前の始まりでまとめて削除出来るはず', function($test) use ($base): void { $cache = new Cache('prefix', $base); foreach (['dnszone-list', 'dnszone-076.moe', 'dnsrecords-076.moe', 'login'] as $n) $cache->set($n, ['x' => 1]); $test->assertEquals(2, $cache->murderPrefix('dnszone-')); $test->assertEquals([], $cache->get('dnszone-list')); $test->assertEquals([], $cache->get('dnszone-076.moe')); $test->assertEquals(1, $cache->get('dnsrecords-076.moe')['x'] ?? null, '他の名前は残る'); $test->assertEquals(1, $cache->get('login')['x'] ?? null); $test->assertEquals(0, $cache->murderPrefix(''), '空は何も消さない'); $test->assertEquals(0, $cache->murderPrefix('../')); $test->assertEquals(1, $cache->get('login')['x'] ?? null); }); $test->it('種類と中身の一覧を出し、全部削除出来るはず', function($test) use ($base): void { $test->assertEquals([], Cache::kinds($base.'/nothing'), 'ディレクトリが無ければ空'); $cache = new Cache('list', $base); $cache->set('b', ['x' => 1]); $cache->set('a', ['y' => 2]); $test->assertTrue(in_array('list', Cache::kinds($base), true)); $entries = $cache->entries(); $test->assertEquals(['a', 'b'], array_column($entries, 'name')); $test->assertTrue($entries[0]['fresh']); $test->assertTrue($entries[0]['size'] > 0); $test->assertTrue(abs($entries[0]['created'] - time()) < 5); $test->assertEquals(2, $cache->murderAll()); $test->assertEquals([], $cache->entries()); $test->assertFalse(is_dir("{$base}/list"), '空のディレクトリも消す'); $test->assertFalse(in_array('list', Cache::kinds($base), true)); }); $test->it('ディレクトリの外のファイル名を拒否するはず', function($test) use ($base): void { $cache = new Cache('test', $base); foreach (['../x', '..', 'a/b', 'a\\b', '', str_repeat('a', 201)] as $bad) { $test->assertFalse($cache->set($bad, [])->isSuccess, "「{$bad}」が拒否されなかった"); $test->assertEquals([], $cache->get($bad)); $test->assertFalse($cache->murder($bad)->isSuccess); } $test->assertThrows(fn() => new Cache('../../etc', $base), \InvalidArgumentException::class); }); }); foreach (glob("{$base}/*/*") ?: [] as $f) @unlink($f); foreach (glob("{$base}/*") ?: [] as $d) @rmdir($d); @rmdir($base); $test->printSummary();