true, 'verboseOutput' => true ]); $base = sys_get_temp_dir().'/lblogs_'.bin2hex(random_bytes(6)); mkdir($base, 0700); $test->describe('ログ', function($test) use ($base): void { $test->it('ディレクトリが無ければ空のはず', function($test) use ($base): void { $logs = new Logs("{$base}/nothing"); $test->assertEquals([], $logs->list()); $test->assertNull($logs->tail('db_log.txt')); $test->assertFalse($logs->clear('db_log.txt')); }); $test->it('ファイルの一覧を出すはず(隠しファイル・ディレクトリを除く)', function($test) use ($base): void { file_put_contents("{$base}/db_log.txt", "a\n"); file_put_contents("{$base}/auth_log.txt", "bb\n"); file_put_contents("{$base}/.hidden", "x"); mkdir("{$base}/sub"); $list = (new Logs($base))->list(); $test->assertEquals(['auth_log.txt', 'db_log.txt'], array_column($list, 'name')); $test->assertEquals(3, $list[0]['size']); }); $test->it('ディレクトリの外のファイルは読めないはず', function($test) use ($base): void { $logs = new Logs("{$base}/sub"); file_put_contents("{$base}/sub/ok.txt", "x\n"); foreach (['../db_log.txt', '..', '.hidden', 'a/b', '', "ok.txt\0"] as $bad) { $test->assertNull($logs->path($bad), $bad); $test->assertNull($logs->tail($bad), $bad); $test->assertFalse($logs->delete($bad), $bad); } $test->assertNotNull($logs->path('ok.txt')); }); $test->it('最後の行を読むはず', function($test) use ($base): void { $logs = new Logs($base); $lines = []; for ($i = 1; $i <= 30000; $i++) $lines[] = "行{$i} ".str_repeat('x', $i % 7); file_put_contents("{$base}/big.txt", implode("\n", $lines)."\n"); $t = $logs->tail('big.txt', 3); $test->assertEquals(['行29998 '.str_repeat('x', 29998 % 7), '行29999 '.str_repeat('x', 29999 % 7), '行30000 '.str_repeat('x', 30000 % 7)], $t['lines']); $test->assertTrue($t['more']); $t = $logs->tail('big.txt', 5000); $test->assertCount(5000, $t['lines']); $test->assertEquals('行25001 '.str_repeat('x', 25001 % 7), $t['lines'][0]); // 最後の改行が無い、CRLF、短いファイル file_put_contents("{$base}/crlf.txt", "a\r\nb\r\nc"); $t = $logs->tail('crlf.txt', 10); $test->assertEquals(['a', 'b', 'c'], $t['lines']); $test->assertFalse($t['more']); file_put_contents("{$base}/empty.txt", ''); $test->assertEquals(['lines' => [], 'more' => false], $logs->tail('empty.txt')); }); $test->it('検索した行だけを読むはず', function($test) use ($base): void { $logs = new Logs($base); $t = $logs->tail('big.txt', 2, '行2999'); $test->assertEquals(['行29998 '.str_repeat('x', 29998 % 7), '行29999 '.str_repeat('x', 29999 % 7)], $t['lines']); $test->assertTrue($t['more']); file_put_contents("{$base}/case.txt", "Error 1\nok\nERROR 2\n"); $test->assertEquals(['Error 1', 'ERROR 2'], $logs->tail('case.txt', 10, 'error')['lines']); $test->assertEquals([], $logs->tail('case.txt', 10, '無い')['lines']); }); $test->it('空にして、削除出来るはず', function($test) use ($base): void { $logs = new Logs($base); $test->assertTrue($logs->clear('case.txt')); clearstatcache(); $test->assertEquals(0, filesize("{$base}/case.txt")); $test->assertTrue($logs->delete('case.txt')); $test->assertFalse(is_file("{$base}/case.txt")); $test->assertFalse($logs->delete('case.txt')); }); }); foreach (glob("{$base}/sub/*") ?: [] as $f) @unlink($f); @rmdir("{$base}/sub"); foreach (glob("{$base}/{,.}*", GLOB_BRACE) ?: [] as $f) if (is_file($f)) @unlink($f); @rmdir($base); $test->printSummary();