1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12use Twig\Cache\FilesystemCache; 13 14require_once \dirname(__DIR__).'/FilesystemHelper.php'; 15 16class Twig_Tests_Cache_FilesystemTest extends \PHPUnit\Framework\TestCase 17{ 18 private $classname; 19 private $directory; 20 private $cache; 21 22 protected function setUp() 23 { 24 $nonce = hash('sha256', uniqid(mt_rand(), true)); 25 $this->classname = '__Twig_Tests_Cache_FilesystemTest_Template_'.$nonce; 26 $this->directory = sys_get_temp_dir().'/twig-test'; 27 $this->cache = new FilesystemCache($this->directory); 28 } 29 30 protected function tearDown() 31 { 32 if (file_exists($this->directory)) { 33 Twig_Tests_FilesystemHelper::removeDir($this->directory); 34 } 35 } 36 37 public function testLoad() 38 { 39 $key = $this->directory.'/cache/cachefile.php'; 40 41 $dir = \dirname($key); 42 @mkdir($dir, 0777, true); 43 $this->assertTrue(is_dir($dir)); 44 $this->assertFalse(class_exists($this->classname, false)); 45 46 $content = $this->generateSource(); 47 file_put_contents($key, $content); 48 49 $this->cache->load($key); 50 51 $this->assertTrue(class_exists($this->classname, false)); 52 } 53 54 public function testLoadMissing() 55 { 56 $key = $this->directory.'/cache/cachefile.php'; 57 58 $this->assertFalse(class_exists($this->classname, false)); 59 60 $this->cache->load($key); 61 62 $this->assertFalse(class_exists($this->classname, false)); 63 } 64 65 public function testWrite() 66 { 67 $key = $this->directory.'/cache/cachefile.php'; 68 $content = $this->generateSource(); 69 70 $this->assertFileNotExists($key); 71 $this->assertFileNotExists($this->directory); 72 73 $this->cache->write($key, $content); 74 75 $this->assertFileExists($this->directory); 76 $this->assertFileExists($key); 77 $this->assertSame(file_get_contents($key), $content); 78 } 79 80 /** 81 * @expectedException \RuntimeException 82 * @expectedExceptionMessage Unable to create the cache directory 83 */ 84 public function testWriteFailMkdir() 85 { 86 if (\defined('PHP_WINDOWS_VERSION_BUILD')) { 87 $this->markTestSkipped('Read-only directories not possible on Windows.'); 88 } 89 90 $key = $this->directory.'/cache/cachefile.php'; 91 $content = $this->generateSource(); 92 93 $this->assertFileNotExists($key); 94 95 // Create read-only root directory. 96 @mkdir($this->directory, 0555, true); 97 $this->assertTrue(is_dir($this->directory)); 98 99 $this->cache->write($key, $content); 100 } 101 102 /** 103 * @expectedException \RuntimeException 104 * @expectedExceptionMessage Unable to write in the cache directory 105 */ 106 public function testWriteFailDirWritable() 107 { 108 if (\defined('PHP_WINDOWS_VERSION_BUILD')) { 109 $this->markTestSkipped('Read-only directories not possible on Windows.'); 110 } 111 112 $key = $this->directory.'/cache/cachefile.php'; 113 $content = $this->generateSource(); 114 115 $this->assertFileNotExists($key); 116 117 // Create root directory. 118 @mkdir($this->directory, 0777, true); 119 // Create read-only subdirectory. 120 @mkdir($this->directory.'/cache', 0555); 121 $this->assertTrue(is_dir($this->directory.'/cache')); 122 123 $this->cache->write($key, $content); 124 } 125 126 /** 127 * @expectedException \RuntimeException 128 * @expectedExceptionMessage Failed to write cache file 129 */ 130 public function testWriteFailWriteFile() 131 { 132 $key = $this->directory.'/cache/cachefile.php'; 133 $content = $this->generateSource(); 134 135 $this->assertFileNotExists($key); 136 137 // Create a directory in the place of the cache file. 138 @mkdir($key, 0777, true); 139 $this->assertTrue(is_dir($key)); 140 141 $this->cache->write($key, $content); 142 } 143 144 public function testGetTimestamp() 145 { 146 $key = $this->directory.'/cache/cachefile.php'; 147 148 $dir = \dirname($key); 149 @mkdir($dir, 0777, true); 150 $this->assertTrue(is_dir($dir)); 151 152 // Create the file with a specific modification time. 153 touch($key, 1234567890); 154 155 $this->assertSame(1234567890, $this->cache->getTimestamp($key)); 156 } 157 158 public function testGetTimestampMissingFile() 159 { 160 $key = $this->directory.'/cache/cachefile.php'; 161 $this->assertSame(0, $this->cache->getTimestamp($key)); 162 } 163 164 /** 165 * Test file cache is tolerant towards trailing (back)slashes on the configured cache directory. 166 * 167 * @dataProvider provideDirectories 168 */ 169 public function testGenerateKey($expected, $input) 170 { 171 $cache = new FilesystemCache($input); 172 $this->assertRegExp($expected, $cache->generateKey('_test_', \get_class($this))); 173 } 174 175 public function provideDirectories() 176 { 177 $pattern = '#a/b/[a-zA-Z0-9]+/[a-zA-Z0-9]+.php$#'; 178 179 return [ 180 [$pattern, 'a/b'], 181 [$pattern, 'a/b/'], 182 [$pattern, 'a/b\\'], 183 [$pattern, 'a/b\\/'], 184 [$pattern, 'a/b\\//'], 185 ['#/'.substr($pattern, 1), '/a/b'], 186 ]; 187 } 188 189 private function generateSource() 190 { 191 return strtr('<?php class {{classname}} {}', [ 192 '{{classname}}' => $this->classname, 193 ]); 194 } 195} 196